* Add support for multiple network interfaces.

This commit is contained in:
Justin Maggard 2011-05-24 17:20:16 +00:00
parent ffd5df4a58
commit 9806103335
6 changed files with 105 additions and 55 deletions

View File

@ -344,7 +344,7 @@ init(int argc, char * * argv)
enum media_types type; enum media_types type;
char * path; char * path;
char real_path[PATH_MAX]; 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 */ /* first check if "-f" option is used */
for(i=2; i<argc; i++) for(i=2; i<argc; i++)
@ -386,13 +386,25 @@ init(int argc, char * * argv)
switch(ary_options[i].id) switch(ary_options[i].id)
{ {
case UPNPIFNAME: 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 ) 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++; n_lan_addr++;
} }
else else
fprintf(stderr, "Interface %s not found, ignoring.\n", ary_options[i].value); 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);
}
}
break; break;
case UPNPLISTENING_IP: case UPNPLISTENING_IP:
if(n_lan_addr < MAX_LAN_ADDR) if(n_lan_addr < MAX_LAN_ADDR)
@ -482,7 +494,8 @@ init(int argc, char * * argv)
} }
break; break;
case UPNPALBUMART_NAMES: 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)); struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s));
int len = strlen(word); int len = strlen(word);
if( word[len-1] == '*' ) if( word[len-1] == '*' )
@ -649,7 +662,7 @@ init(int argc, char * * argv)
int address_already_there = 0; int address_already_there = 0;
int j; int j;
i++; 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", fprintf(stderr, "Network interface '%s' not found.\n",
argv[i]); argv[i]);
@ -658,7 +671,7 @@ init(int argc, char * * argv)
for(j=0; j<n_lan_addr; j++) for(j=0; j<n_lan_addr; j++)
{ {
struct lan_addr_s tmpaddr; struct lan_addr_s tmpaddr;
parselanaddr(&tmpaddr, ext_ip_addr); parselanaddr(&tmpaddr, ip_addr);
if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
address_already_there = 1; address_already_there = 1;
} }
@ -666,7 +679,7 @@ init(int argc, char * * argv)
break; break;
if(n_lan_addr < MAX_LAN_ADDR) 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++; n_lan_addr++;
} }
else else
@ -699,13 +712,13 @@ init(int argc, char * * argv)
/* If no IP was specified, try to detect one */ /* If no IP was specified, try to detect one */
if( n_lan_addr < 1 ) if( n_lan_addr < 1 )
{ {
if( (getsysaddr(ext_ip_addr, sizeof(ext_ip_addr)) < 0) && if( (getsysaddr(ip_addr, sizeof(ip_addr)) < 0) &&
(getifaddr("eth0", ext_ip_addr, sizeof(ext_ip_addr)) < 0) && (getifaddr("eth0", ip_addr, sizeof(ip_addr)) < 0) &&
(getifaddr("eth1", ext_ip_addr, sizeof(ext_ip_addr)) < 0) ) (getifaddr("eth1", ip_addr, sizeof(ip_addr)) < 0) )
{ {
DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); 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++; n_lan_addr++;
} }

View File

@ -51,8 +51,6 @@
#include "upnpglobalvars.h" #include "upnpglobalvars.h"
#include "log.h" #include "log.h"
static struct aBeacon* topBeacon = NULL;
/* OpenAndConfHTTPSocket() : /* OpenAndConfHTTPSocket() :
* setup the socket used to handle incoming HTTP connections. */ * setup the socket used to handle incoming HTTP connections. */
int int
@ -187,8 +185,6 @@ rcvBeaconMessage(char * beacon)
char * cp; char * cp;
char * scp; char * scp;
char * tokptr; char * tokptr;
struct aBeacon * b;
time_t current;
cp = strtok_r(beacon, "=\r\n", &tokptr); cp = strtok_r(beacon, "=\r\n", &tokptr);
while( cp != NULL ) while( cp != NULL )
@ -217,6 +213,14 @@ rcvBeaconMessage(char * beacon)
if( strcmp(identity, uuidvalue) == 0) if( strcmp(identity, uuidvalue) == 0)
return 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); current = time(NULL);
for( b = topBeacon; b != NULL; b = b->next ) for( b = topBeacon; b != NULL; b = b->next )
{ {
@ -241,10 +245,6 @@ rcvBeaconMessage(char * beacon)
platform ? platform : "-", platform ? platform : "-",
services ? services : "-" ); services ? services : "-" );
} }
#ifdef DEBUG
int len;
char buf[32];
static time_t lastSummary = 0;
b->lastSeen = current; b->lastSeen = current;
if( !lastSummary ) if( !lastSummary )
@ -292,6 +292,21 @@ void ProcessTiVoBeacon(int s)
(struct sockaddr *)&sendername, &len_r); (struct sockaddr *)&sendername, &len_r);
if( n > 0 ) if( n > 0 )
bufr[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++ ) for( cp = bufr; *cp; cp++ )
/* do nothing */; /* do nothing */;
if( cp[-1] == '\r' || cp[-1] == '\n' ) if( cp[-1] == '\r' || cp[-1] == '\n' )

View File

@ -263,7 +263,24 @@ intervening space) by either an integer or the keyword "infinite". */
} }
else if(strncasecmp(line, "Host", 4)==0) else if(strncasecmp(line, "Host", 4)==0)
{ {
int i;
h->reqflags |= FLAG_HOST; 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) 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 ) 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", 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);
} }
} }

View File

@ -57,6 +57,7 @@ enum httpCommands {
struct upnphttp { struct upnphttp {
int socket; int socket;
struct in_addr clientaddr; /* client address */ struct in_addr clientaddr; /* client address */
int iface;
int state; int state;
char HttpVer[16]; char HttpVer[16];
/* request */ /* request */
@ -77,11 +78,11 @@ struct upnphttp {
off_t req_RangeEnd; off_t req_RangeEnd;
long int req_chunklen; long int req_chunklen;
uint32_t reqflags; uint32_t reqflags;
uint32_t respflags;
/* response */ /* response */
char * res_buf; char * res_buf;
int res_buflen; int res_buflen;
int res_buf_alloclen; int res_buf_alloclen;
uint32_t respflags;
/*int res_contentlen;*/ /*int res_contentlen;*/
/*int res_contentoff;*/ /* header length */ /*int res_contentoff;*/ /* header length */
LIST_ENTRY(upnphttp) entries; LIST_ENTRY(upnphttp) entries;

View File

@ -552,16 +552,16 @@ parse_sort_criteria(char * sortCriteria, int * error)
inline static void inline static void
add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, 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 dstw = reqw;
int dsth = reqh; int dsth = reqh;
if( passed_args->flags & FLAG_NO_RESIZE ) if( args->flags & FLAG_NO_RESIZE )
return; return;
strcatf(passed_args->str, "&lt;res "); strcatf(args->str, "&lt;res ");
if( passed_args->filter & FILTER_RES_RESOLUTION ) if( args->filter & FILTER_RES_RESOLUTION )
{ {
dstw = reqw; dstw = reqw;
dsth = ((((reqw<<10)/srcw)*srch)>>10); 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; dsth = reqh;
dstw = (((reqh<<10)/srch) * srcw>>10); 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\"&gt;" strcatf(args->str, "protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=%s;DLNA.ORG_CI=1\"&gt;"
"http://%s:%d/Resized/%s.jpg?width=%d,height=%d" "http://%s:%d/Resized/%s.jpg?width=%d,height=%d"
"&lt;/res&gt;", "&lt;/res&gt;",
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 inline static void
add_res(char *size, char *duration, char *bitrate, char *sampleFrequency, add_res(char *size, char *duration, char *bitrate, char *sampleFrequency,
char *nrAudioChannels, char *resolution, char *dlna_pn, char *mime, 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, "&lt;res "); strcatf(args->str, "&lt;res ");
if( size && (passed_args->filter & FILTER_RES_SIZE) ) { if( size && (args->filter & FILTER_RES_SIZE) ) {
strcatf(passed_args->str, "size=\"%s\" ", size); strcatf(args->str, "size=\"%s\" ", size);
} }
if( duration && (passed_args->filter & FILTER_RES_DURATION) ) { if( duration && (args->filter & FILTER_RES_DURATION) ) {
strcatf(passed_args->str, "duration=\"%s\" ", duration); strcatf(args->str, "duration=\"%s\" ", duration);
} }
if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) { if( bitrate && (args->filter & FILTER_RES_BITRATE) ) {
strcatf(passed_args->str, "bitrate=\"%s\" ", bitrate); strcatf(args->str, "bitrate=\"%s\" ", bitrate);
} }
if( sampleFrequency && (passed_args->filter & FILTER_RES_SAMPLEFREQUENCY) ) { if( sampleFrequency && (args->filter & FILTER_RES_SAMPLEFREQUENCY) ) {
strcatf(passed_args->str, "sampleFrequency=\"%s\" ", sampleFrequency); strcatf(args->str, "sampleFrequency=\"%s\" ", sampleFrequency);
} }
if( nrAudioChannels && (passed_args->filter & FILTER_RES_NRAUDIOCHANNELS) ) { if( nrAudioChannels && (args->filter & FILTER_RES_NRAUDIOCHANNELS) ) {
strcatf(passed_args->str, "nrAudioChannels=\"%s\" ", nrAudioChannels); strcatf(args->str, "nrAudioChannels=\"%s\" ", nrAudioChannels);
} }
if( resolution && (passed_args->filter & FILTER_RES_RESOLUTION) ) { if( resolution && (args->filter & FILTER_RES_RESOLUTION) ) {
strcatf(passed_args->str, "resolution=\"%s\" ", resolution); strcatf(args->str, "resolution=\"%s\" ", resolution);
} }
strcatf(passed_args->str, "protocolInfo=\"http-get:*:%s:%s\"&gt;" strcatf(args->str, "protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:%d/MediaItems/%s.%s" "http://%s:%d/MediaItems/%s.%s"
"&lt;/res&gt;", "&lt;/res&gt;",
mime, dlna_pn, lan_addr[0].str, mime, dlna_pn, lan_addr[args->iface].str,
runtime_vars.port, detailID, ext); runtime_vars.port, detailID, ext);
} }
@ -756,14 +757,14 @@ callback(void *args, int argc, char **argv, char **azColName)
ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN\"&gt;" ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN\"&gt;"
"http://%s:%d/AlbumArt/%s-%s.jpg" "http://%s:%d/AlbumArt/%s-%s.jpg"
"&lt;/res&gt;", "&lt;/res&gt;",
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 ) { } else if( passed_args->filter & FILTER_UPNP_ALBUMARTURI ) {
ret = strcatf(str, "&lt;upnp:albumArtURI"); ret = strcatf(str, "&lt;upnp:albumArtURI");
if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) { 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, " dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"");
} }
ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;", ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
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 #ifdef PFS_HACK
@ -774,12 +775,12 @@ callback(void *args, int argc, char **argv, char **azColName)
ret = strcatf(str, "&lt;upnp:albumArtURI&gt;" ret = strcatf(str, "&lt;upnp:albumArtURI&gt;"
"http://%s:%d/Thumbnails/%s.jpg" "http://%s:%d/Thumbnails/%s.jpg"
"&lt;/upnp:albumArtURI&gt;", "&lt;/upnp:albumArtURI&gt;",
lan_addr[0].str, runtime_vars.port, detailID); lan_addr[passed_args->iface].str, runtime_vars.port, detailID);
} else { } else {
ret = strcatf(str, "&lt;upnp:albumArtURI&gt;" ret = strcatf(str, "&lt;upnp:albumArtURI&gt;"
"http://%s:%d/Resized/%s.jpg?width=160,height=160" "http://%s:%d/Resized/%s.jpg?width=160,height=160"
"&lt;/upnp:albumArtURI&gt;", "&lt;/upnp:albumArtURI&gt;",
lan_addr[0].str, runtime_vars.port, detailID); lan_addr[passed_args->iface].str, runtime_vars.port, detailID);
} }
} }
#endif #endif
@ -789,7 +790,7 @@ callback(void *args, int argc, char **argv, char **azColName)
ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;" ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:%d/Thumbnails/%s.jpg" "http://%s:%d/Thumbnails/%s.jpg"
"&lt;/res&gt;", "&lt;/res&gt;",
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); runtime_vars.port, detailID);
} }
add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels,
@ -809,7 +810,7 @@ callback(void *args, int argc, char **argv, char **azColName)
ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;" ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:%s:%s\"&gt;"
"http://%s:%d/Thumbnails/%s.jpg" "http://%s:%d/Thumbnails/%s.jpg"
"&lt;/res&gt;", "&lt;/res&gt;",
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); runtime_vars.port, detailID);
} }
} }
@ -886,7 +887,7 @@ callback(void *args, int argc, char **argv, char **azColName)
ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:text/srt:*\"&gt;" ret = strcatf(str, "&lt;res protocolInfo=\"http-get:*:text/srt:*\"&gt;"
"http://%s:%d/Captions/%s.srt" "http://%s:%d/Captions/%s.srt"
"&lt;/res&gt;", "&lt;/res&gt;",
lan_addr[0].str, runtime_vars.port, detailID); lan_addr[passed_args->iface].str, runtime_vars.port, detailID);
} }
break; break;
default: 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, "dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\"");
} }
ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;", ret = strcatf(str, "&gt;http://%s:%d/AlbumArt/%s-%s.jpg&lt;/upnp:albumArtURI&gt;",
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, "&lt;/container&gt;"); ret = strcatf(str, "&lt;/container&gt;");
} }
@ -997,6 +998,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
str.off = sprintf(str.data, "%s", resp0); str.off = sprintf(str.data, "%s", resp0);
args.str = &str; args.str = &str;
/* See if we need to include DLNA namespace reference */ /* See if we need to include DLNA namespace reference */
args.iface = h->iface;
args.filter = set_filter_flags(Filter, h->req_client); args.filter = set_filter_flags(Filter, h->req_client);
if( args.filter & FILTER_DLNA_NAMESPACE ) if( args.filter & FILTER_DLNA_NAMESPACE )
{ {
@ -1174,6 +1176,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
str.size = DEFAULT_RESP_SIZE; str.size = DEFAULT_RESP_SIZE;
str.off = sprintf(str.data, "%s", resp0); str.off = sprintf(str.data, "%s", resp0);
/* See if we need to include DLNA namespace reference */ /* See if we need to include DLNA namespace reference */
args.iface = h->iface;
args.filter = set_filter_flags(Filter, h->req_client); args.filter = set_filter_flags(Filter, h->req_client);
if( args.filter & FILTER_DLNA_NAMESPACE ) if( args.filter & FILTER_DLNA_NAMESPACE )
{ {

View File

@ -37,6 +37,7 @@ struct Response
int start; int start;
int returned; int returned;
int requested; int requested;
int iface;
uint32_t filter; uint32_t filter;
uint32_t flags; uint32_t flags;
enum client_types client; enum client_types client;