diff --git a/Makefile.am b/Makefile.am index a02d8b1..c3aa4c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ SUBDIRS=po sbin_PROGRAMS = minidlnad check_PROGRAMS = testupnpdescgen minidlnad_SOURCES = minidlna.c upnphttp.c upnpdescgen.c upnpsoap.c \ - upnpreplyparse.c minixml.c \ + upnpreplyparse.c minixml.c clients.c \ getifaddr.c daemonize.c upnpglobalvars.c \ options.c minissdp.c uuid.c upnpevents.c \ sql.c utils.c metadata.c scanner.c inotify.c \ diff --git a/clients.c b/clients.c new file mode 100644 index 0000000..e50a883 --- /dev/null +++ b/clients.c @@ -0,0 +1,251 @@ +#include +#include +#include + +#include "clients.h" +#include "getifaddr.h" +#include "log.h" + +struct client_type_s client_types[] = +{ + { 0, + 0, + "Unknown", + NULL, + EMatchNone + }, + + { EXbox, + FLAG_MIME_AVI_AVI | FLAG_MS_PFS, + "Xbox 360", + "Xbox/", + EUserAgent + }, + + { EPS3, + FLAG_DLNA | FLAG_MIME_AVI_DIVX, + "PLAYSTATION 3", + "PLAYSTATION", + EUserAgent + }, + + { EPS3, + FLAG_DLNA | FLAG_MIME_AVI_DIVX, + "PLAYSTATION 3", + "PLAYSTATION 3", + EXAVClientInfo + }, + + { ESamsungSeriesCTV, + FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE | FLAG_SAMSUNG_TV, + "Samsung Series C TV", + "SEC_HHP_TV", + EUserAgent + }, + + /* User-Agent: DLNADOC/1.50 SEC_HHP_BD-D5100/1.0 */ + { ESamsungSeriesC, + FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, + "Samsung Series C", + "SEC_HHP_", + EUserAgent + }, + + { ESamsungSeriesA, + FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, + "Samsung Series A", + "SamsungWiselinkPro", + EUserAgent + }, + + { ESamsungSeriesB, + FLAG_SAMSUNG | FLAG_DLNA | FLAG_NO_RESIZE, + "Samsung Series B", + "Samsung DTV DMR", + EModelName + }, + + /* User-Agent: Panasonic MIL DLNA CP UPnP/1.0 DLNADOC/1.50 */ + { EPanasonic, + FLAG_DLNA | FLAG_FORCE_SORT, + "Panasonic", + "Panasonic", + EUserAgent + }, + + { EDenonReceiver, + FLAG_DLNA, + "Denon Receiver", + "bridgeCo-DMP/3", + EUserAgent + }, + + { EFreeBox, + FLAG_RESIZE_THUMBS, + "FreeBox", + "fbxupnpav/", + EUserAgent + }, + + { EPopcornHour, + FLAG_MIME_FLAC_FLAC, + "Popcorn Hour", + "SMP8634", + EUserAgent + }, + + /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Blu-ray Disc Player"; mv="2.0" */ + /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BLU-RAY HOME THEATRE SYSTEM"; mv="2.0"; */ + /* Sony SMP-100 needs the same treatment as their BDP-S370 */ + /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Media Player"; mv="2.0" */ + { ESonyBDP, + FLAG_DLNA, + "Sony BDP", + "mv=\"2.0\"", + EXAVClientInfo + }, + + /* User-Agent: Linux/2.6.31-1.0 UPnP/1.0 DLNADOC/1.50 INTEL_NMPR/2.0 LGE_DLNA_SDK/1.5.0 */ + { ELGDevice, + FLAG_DLNA, + "LG", + "LGE_DLNA_SDK", + EUserAgent + }, + + /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BRAVIA KDL-40EX503"; mv="1.7"; */ + { ESonyBravia, + FLAG_DLNA, + "Sony Bravia", + "BRAVIA", + EXAVClientInfo + }, + + /* X-AV-Client-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="INTERNET TV NSX-40GT 1"; mv="0.1"; */ + { ESonyInternetTV, + FLAG_DLNA, + "Sony Internet TV", + "INTERNET TV", + EXAVClientInfo + }, + + { ENetgearEVA2000, + FLAG_MS_PFS | FLAG_RESIZE_THUMBS, + "EVA2000", + "Verismo,", + EUserAgent + }, + + { EDirecTV, + FLAG_RESIZE_THUMBS, + "DirecTV", + "DIRECTV ", + EUserAgent + }, + + { EToshibaTV, + FLAG_DLNA, + "Toshiba TV", + "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", + EUserAgent + }, + + { ERokuSoundBridge, + FLAG_MS_PFS | FLAG_AUDIO_ONLY | FLAG_MIME_WAV_WAV | FLAG_FORCE_SORT, + "Roku SoundBridge", + "Roku SoundBridge", + EModelName + }, + + { EMarantzDMP, + FLAG_DLNA | FLAG_MIME_WAV_WAV, + "marantz DMP", + "marantz DMP", + EFriendlyNameSSDP + }, + + { EMediaRoom, + FLAG_MS_PFS, + "MS MediaRoom", + "Microsoft-IPTV-Client", + EUserAgent + }, + + { ELifeTab, + FLAG_MS_PFS, + "LIFETAB", + "LIFETAB", + EFriendlyName + }, + + { EStandardDLNA150, + FLAG_DLNA | FLAG_MIME_AVI_AVI, + "Generic DLNA 1.5", + "DLNADOC/1.50", + EUserAgent + }, + + { 0, 0, NULL, 0 } +}; + +struct client_cache_s clients[CLIENT_CACHE_SLOTS]; + +int +SearchClientCache(struct in_addr addr, int quiet) +{ + int i; + + for (i = 0; i < CLIENT_CACHE_SLOTS; i++) + { + if (clients[i].addr.s_addr == addr.s_addr) + { + /* Invalidate this client cache if it's older than 1 hour */ + if ((time(NULL) - clients[i].age) > 3600) + { + unsigned char mac[6]; + if (get_remote_mac(addr, mac) == 0 && + memcmp(mac, clients[i].mac, 6) == 0) + { + /* Same MAC as last time when we were able to identify the client, + * so extend the timeout by another hour. */ + clients[i].age = time(NULL); + } + else + { + memset(&clients[i], 0, sizeof(struct client_cache_s)); + return -1; + } + } + if (!quiet) + DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [%s/entry %d]\n", + client_types[clients[i].type].name, i); + return i; + } + } + + return -1; +} + +int +AddClientCache(struct in_addr addr, int type) +{ + int i; + + for (i = 0; i < CLIENT_CACHE_SLOTS; i++) + { + if (clients[i].addr.s_addr) + continue; + get_remote_mac(addr, clients[i].mac); + clients[i].addr = addr; + clients[i].type = type; + clients[i].age = time(NULL); + DPRINTF(E_DEBUG, L_HTTP, "Added client [%s/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", + client_types[type].name, inet_ntoa(clients[i].addr), + clients[i].mac[0], clients[i].mac[1], clients[i].mac[2], + clients[i].mac[3], clients[i].mac[4], clients[i].mac[5], i); + return 0; + } + + return -1; +} + diff --git a/clients.h b/clients.h new file mode 100644 index 0000000..d3ffe1d --- /dev/null +++ b/clients.h @@ -0,0 +1,76 @@ +#ifndef __CLIENTS_H__ +#define __CLIENTS_H__ +#include +#include + +#define CLIENT_CACHE_SLOTS 20 + +#define FLAG_DLNA 0x00000001 +#define FLAG_MIME_AVI_DIVX 0x00000002 +#define FLAG_MIME_AVI_AVI 0x00000004 +#define FLAG_MIME_FLAC_FLAC 0x00000008 +#define FLAG_MIME_WAV_WAV 0x00000010 +#define FLAG_RESIZE_THUMBS 0x00000020 +#define FLAG_NO_RESIZE 0x00000040 +#define FLAG_MS_PFS 0x00000080 // Microsoft PlaysForSure client +#define FLAG_SAMSUNG 0x00000100 +#define FLAG_SAMSUNG_TV 0x00000200 +#define FLAG_AUDIO_ONLY 0x00000400 +#define FLAG_FORCE_SORT 0x00000800 + +enum match_types { + EMatchNone, + EUserAgent, + EXAVClientInfo, + EFriendlyName, + EModelName, + EFriendlyNameSSDP +}; + +enum client_types { + EXbox = 1, + EPS3, + EDenonReceiver, + EDirecTV, + EFreeBox, + ELGDevice, + ELifeTab, + EMarantzDMP, + EMediaRoom, + ENetgearEVA2000, + EPanasonic, + EPopcornHour, + ERokuSoundBridge, + ESamsungSeriesA, + ESamsungSeriesB, + ESamsungSeriesC, + ESamsungSeriesCTV, + ESonyBDP, + ESonyBravia, + ESonyInternetTV, + EToshibaTV, + EStandardDLNA150 +}; + +struct client_type_s { + enum client_types type; + uint32_t flags; + const char *name; + const char *match; + enum match_types match_type; +}; + +struct client_cache_s { + struct in_addr addr; + unsigned char mac[6]; + enum client_types type; + time_t age; +}; + +extern struct client_type_s client_types[]; +extern struct client_cache_s clients[CLIENT_CACHE_SLOTS]; + +int SearchClientCache(struct in_addr addr, int quiet); +int AddClientCache(struct in_addr addr, int type); + +#endif diff --git a/getifaddr.c b/getifaddr.c index f5c2e08..c673391 100644 --- a/getifaddr.c +++ b/getifaddr.c @@ -326,7 +326,7 @@ getsyshwaddr(char * buf, int len) } int -get_remote_mac(struct in_addr ip_addr, unsigned char * mac) +get_remote_mac(struct in_addr ip_addr, unsigned char *mac) { struct in_addr arp_ent; FILE * arp; diff --git a/minidlnatypes.h b/minidlnatypes.h index 4bc6833..bda1959 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -30,7 +30,8 @@ #define __MINIDLNATYPES_H__ #include "config.h" -#include +#include "clients.h" +//#include #include #include @@ -66,28 +67,6 @@ enum file_types { TYPE_FILE }; -enum client_types { - EXbox = 1, - EPS3, - ESamsungSeriesC, - EDenonReceiver, - EFreeBox, - EPopcornHour, - EMediaRoom, - ESonyBDP, - ESonyBravia, - ERokuSoundBridge, - EToshibaTV, - ELGDevice, - ENetgearEVA2000, - ESamsungSeriesA, - ESamsungSeriesB, - EMarantzDMP, - ELifeTab, - EDirecTV, - EStandardDLNA150 = 100 -}; - struct media_dir_s { char *path; /* base path */ media_types types; /* types of files to scan */ @@ -100,12 +79,4 @@ struct album_art_name_s { struct album_art_name_s *next; }; -struct client_cache_s { - struct in_addr addr; - unsigned char mac[6]; - enum client_types type; - uint32_t flags; - time_t age; -}; - #endif diff --git a/minissdp.c b/minissdp.c index 3b69582..59267e5 100644 --- a/minissdp.c +++ b/minissdp.c @@ -346,8 +346,7 @@ ParseUPnPClient(char *location) int content_len = sizeof(buf); struct NameValueParserData xml; int client; - enum client_types type = 0; - uint32_t flags = 0; + int type = 0; char *model, *serial, *name; if (strncmp(location, "http://", 7) != 0) @@ -437,33 +436,46 @@ close: name = GetValueFromNameValueList(&xml, "friendlyName"); if (model) { + int i; DPRINTF(E_DEBUG, L_SSDP, "Model: %s\n", model); - if (strstr(model, "Roku SoundBridge") != NULL) + for (i = 0; client_types[i].name; i++) { - type = ERokuSoundBridge; - flags |= FLAG_MS_PFS; - flags |= FLAG_AUDIO_ONLY; - flags |= FLAG_MIME_WAV_WAV; - } - else if ((strcmp(model, "Samsung DTV DMR") == 0) && serial ) - { - DPRINTF(E_DEBUG, L_SSDP, "Serial: %s\n", serial); - /* The Series B I saw was 20081224DMR. Series A should be older than that. */ - if (atoi(serial) > 20081200) + if (client_types[i].match_type != EModelName) + continue; + if (strstr(model, client_types[i].match) != NULL) { - type = ESamsungSeriesB; - flags |= FLAG_SAMSUNG; - flags |= FLAG_DLNA; - flags |= FLAG_NO_RESIZE; + type = i; + break; } } - else + + /* Special Samsung handling. It's very hard to tell Series A from B */ + if (type > 0 && client_types[type].type == ESamsungSeriesB) { - if (name && (strcmp(name, "marantz DMP") == 0)) + if (serial) { - type = EMarantzDMP; - flags |= FLAG_DLNA; - flags |= FLAG_MIME_WAV_WAV; + DPRINTF(E_DEBUG, L_SSDP, "Serial: %s\n", serial); + /* The Series B I saw was 20081224DMR. Series A should be older than that. */ + if (atoi(serial) < 20081201) + type = 0; + } + else + { + type = 0; + } + } + + if (type == 0 && name != NULL) + { + for (i = 0; client_types[i].name; i++) + { + if (client_types[i].match_type != EFriendlyNameSSDP) + continue; + if (strcmp(name, client_types[i].match) == 0) + { + type = i; + break; + } } } } @@ -474,22 +486,13 @@ close: client = SearchClientCache(dest.sin_addr, 1); if (client < 0) { - for (client=0; client #include "minidlnatypes.h" +#include "clients.h" #include "config.h" #include @@ -64,7 +65,6 @@ # define SERVER_NAME "MiniDLNA" #endif -#define CLIENT_CACHE_SLOTS 20 #define USE_FORK 1 #define DB_VERSION 9 @@ -194,7 +194,7 @@ extern uint32_t runtime_flags; #define GETFLAG(mask) (runtime_flags & mask) #define CLEARFLAG(mask) runtime_flags &= ~mask -extern const char * pidfilename; +extern const char *pidfilename; extern char uuidvalue[]; @@ -229,9 +229,8 @@ extern sqlite3 *db; extern char friendly_name[]; extern char db_path[]; extern char log_path[]; -extern struct media_dir_s * media_dirs; -extern struct album_art_name_s * album_art_names; -extern struct client_cache_s clients[CLIENT_CACHE_SLOTS]; +extern struct media_dir_s *media_dirs; +extern struct album_art_name_s *album_art_names; extern short int scanning; extern volatile short int quitting; extern volatile uint32_t updateID; diff --git a/upnphttp.c b/upnphttp.c index dc11eda..7de4e7a 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -77,6 +77,7 @@ #include #include "tivo_utils.h" #include "tivo_commands.h" +#include "clients.h" #include "sendfile.h" @@ -130,40 +131,6 @@ Delete_upnphttp(struct upnphttp * h) } } -int -SearchClientCache(struct in_addr addr, int quiet) -{ - int i; - for( i=0; i 3600 ) - { - unsigned char mac[6]; - if( get_remote_mac(addr, mac) == 0 && - memcmp(mac, clients[i].mac, 6) == 0 ) - { - /* Same MAC as last time when we were able to identify the client, - * so extend the timeout by another hour. */ - clients[i].age = time(NULL); - } - else - { - memset(&clients[i], 0, sizeof(struct client_cache_s)); - return -1; - } - } - if( !quiet ) - DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [type %d/entry %d]\n", - clients[i].type, i); - return i; - } - } - return -1; -} - /* parse HttpHeaders of the REQUEST */ static void ParseHttpHeaders(struct upnphttp * h) @@ -302,121 +269,42 @@ ParseHttpHeaders(struct upnphttp * h) } else if(strncasecmp(line, "User-Agent", 10)==0) { - char *s; + int i; /* Skip client detection if we already detected it. */ if( h->req_client ) goto next_header; p = colon + 1; while(isspace(*p)) p++; - if(strncasecmp(p, "Xbox/", 5)==0) + for (i = 0; client_types[i].name; i++) { - h->req_client = EXbox; - h->reqflags |= FLAG_MIME_AVI_AVI; - h->reqflags |= FLAG_MS_PFS; - } - else if(strncmp(p, "PLAYSTATION", 11)==0) - { - h->req_client = EPS3; - h->reqflags |= FLAG_DLNA; - h->reqflags |= FLAG_MIME_AVI_DIVX; - } - else if((s=strstrc(p, "SEC_HHP_", '\r'))) - { - h->req_client = ESamsungSeriesC; - h->reqflags |= FLAG_SAMSUNG; - h->reqflags |= FLAG_DLNA; - h->reqflags |= FLAG_NO_RESIZE; - if(strstrc(s+8, "TV", '\r')) - h->reqflags |= FLAG_SAMSUNG_TV; - } - else if(strncmp(p, "SamsungWiselinkPro", 18)==0) - { - h->req_client = ESamsungSeriesA; - h->reqflags |= FLAG_SAMSUNG; - h->reqflags |= FLAG_DLNA; - h->reqflags |= FLAG_NO_RESIZE; - } - else if(strstrc(p, "bridgeCo-DMP/3", '\r')) - { - h->req_client = EDenonReceiver; - h->reqflags |= FLAG_DLNA; - } - else if(strstrc(p, "fbxupnpav/", '\r')) - { - h->req_client = EFreeBox; - h->reqflags |= FLAG_RESIZE_THUMBS; - } - else if(strncmp(p, "SMP8634", 7)==0) - { - h->req_client = EPopcornHour; - h->reqflags |= FLAG_MIME_FLAC_FLAC; - } - else if(strstrc(p, "Microsoft-IPTV-Client", '\r')) - { - h->req_client = EMediaRoom; - h->reqflags |= FLAG_MS_PFS; - } - else if(strstrc(p, "LGE_DLNA_SDK", '\r')) - { - h->req_client = ELGDevice; - h->reqflags |= FLAG_DLNA; - } - else if(strncmp(p, "Verismo,", 8)==0) - { - h->req_client = ENetgearEVA2000; - h->reqflags |= FLAG_MS_PFS; - h->reqflags |= FLAG_RESIZE_THUMBS; - } - else if(strstrc(p, "DIRECTV ", '\r')) - { - h->req_client = EDirecTV; - h->reqflags |= FLAG_RESIZE_THUMBS; - } - else if(strstrc(p, "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", '\r')) - { - h->req_client = EToshibaTV; - h->reqflags |= FLAG_DLNA; - } - else if(strstrc(p, "DLNADOC/1.50", '\r')) - { - h->req_client = EStandardDLNA150; - h->reqflags |= FLAG_DLNA; - h->reqflags |= FLAG_MIME_AVI_AVI; + if (client_types[i].match_type != EUserAgent) + continue; + if (strstrc(p, client_types[i].match, '\r') != NULL) + { + h->req_client = i; + break; + } } } else if(strncasecmp(line, "X-AV-Client-Info", 16)==0) { + int i; /* Skip client detection if we already detected it. */ - if( h->req_client && h->req_client < EStandardDLNA150 ) + if( h->req_client && client_types[h->req_client].type < EStandardDLNA150 ) goto next_header; p = colon + 1; while(isspace(*p)) p++; - if(strstrc(p, "PLAYSTATION 3", '\r')) + for (i = 0; client_types[i].name; i++) { - h->req_client = EPS3; - h->reqflags |= FLAG_DLNA; - h->reqflags |= FLAG_MIME_AVI_DIVX; - } - /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Blu-ray Disc Player"; mv="2.0" */ - /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BLU-RAY HOME THEATRE SYSTEM"; mv="2.0"; */ - /* Sony SMP-100 needs the same treatment as their BDP-S370 */ - /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="Media Player"; mv="2.0" */ - else if(strstrc(p, "Blu-ray Disc Player", '\r') || - strstrc(p, "BLU-RAY HOME THEATRE SYSTEM", '\r') || - strstrc(p, "Media Player", '\r')) - { - h->req_client = ESonyBDP; - h->reqflags |= FLAG_DLNA; - } - /* X-AV-Client-Info: av=5.0; cn="Sony Corporation"; mn="BRAVIA KDL-40EX503"; mv="1.7"; */ - /* X-AV-Client-Info: av=5.0; hn=""; cn="Sony Corporation"; mn="INTERNET TV NSX-40GT 1"; mv="0.1"; */ - else if(strstrc(p, "BRAVIA", '\r') || - strstrc(p, "INTERNET TV", '\r')) - { - h->req_client = ESonyBravia; - h->reqflags |= FLAG_DLNA; + if (client_types[i].match_type != EXAVClientInfo) + continue; + if (strstrc(p, client_types[i].match, '\r') != NULL) + { + h->req_client = i; + break; + } } } else if(strncasecmp(line, "Transfer-Encoding", 17)==0) @@ -485,13 +373,19 @@ ParseHttpHeaders(struct upnphttp * h) } else if(strncasecmp(line, "FriendlyName", 12)==0) { + int i; p = colon + 1; while(isspace(*p)) p++; - if(strstrc(p, "LIFETAB", '\r')) + for (i = 0; client_types[i].name; i++) { - h->req_client = ELifeTab; - h->reqflags |= FLAG_MS_PFS; + if (client_types[i].match_type != EFriendlyName) + continue; + if (strstrc(p, client_types[i].match, '\r') != NULL) + { + h->req_client = i; + break; + } } } } @@ -532,35 +426,26 @@ next_header: /* Add this client to the cache if it's not there already. */ if( n < 0 ) { - for( n=0; nclientaddr, clients[n].mac); - clients[n].addr = h->clientaddr; - DPRINTF(E_DEBUG, L_HTTP, "Added client [%d/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n", - h->req_client, inet_ntoa(clients[n].addr), - clients[n].mac[0], clients[n].mac[1], clients[n].mac[2], - clients[n].mac[3], clients[n].mac[4], clients[n].mac[5], n); - break; - } + AddClientCache(h->clientaddr, h->req_client); } - else if( (clients[n].type < EStandardDLNA150 && h->req_client == EStandardDLNA150) || - (clients[n].type == ESamsungSeriesB && h->req_client == ESamsungSeriesA) ) + else { + enum client_types type = client_types[h->req_client].type; + enum client_types ctype = client_types[clients[n].type].type; /* If we know the client and our new detection is generic, use our cached info */ /* If we detected a Samsung Series B earlier, don't overwrite it with Series A info */ - h->reqflags |= clients[n].flags; - h->req_client = clients[n].type; - return; + if ((ctype < EStandardDLNA150 && type == EStandardDLNA150) || + (ctype == ESamsungSeriesB && type == ESamsungSeriesA)) + { + h->req_client = clients[n].type; + return; + } + clients[n].type = h->req_client; + clients[n].age = time(NULL); } - clients[n].type = h->req_client; - clients[n].flags = h->reqflags & 0xFFF00000; - clients[n].age = time(NULL); } else if( n >= 0 ) { - h->reqflags |= clients[n].flags; h->req_client = clients[n].type; } } @@ -979,7 +864,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h) if(strcmp(ROOTDESC_PATH, HttpUrl) == 0) { /* If it's a Xbox360, we might need a special friendly_name to be recognized */ - if( h->req_client == EXbox ) + if( client_types[h->req_client].type == EXbox ) { char model_sav[2]; i = 0; @@ -995,7 +880,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h) friendly_name[i] = '\0'; memcpy(modelnumber, model_sav, 2); } - else if( h->reqflags & FLAG_SAMSUNG_TV ) + else if( client_types[h->req_client].flags & FLAG_SAMSUNG_TV ) { sendXMLdesc(h, genRootDescSamsung); } @@ -1837,7 +1722,7 @@ resized_error: } void -SendResp_dlnafile(struct upnphttp * h, char * object) +SendResp_dlnafile(struct upnphttp *h, char *object) { char header[1024]; struct string_s str; @@ -1850,6 +1735,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) int64_t id; int sendfh; uint32_t dlna_flags = DLNA_FLAG_DLNA_V1_5|DLNA_FLAG_HTTP_STALLING|DLNA_FLAG_TM_B; + uint32_t cflags = client_types[h->req_client].flags; static struct { int64_t id; enum client_types client; char path[PATH_MAX]; @@ -1861,7 +1747,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) #endif id = strtoll(object, NULL, 10); - if( h->reqflags & FLAG_MS_PFS ) + if( cflags & FLAG_MS_PFS ) { if( strstr(object, "?albumArt=true") ) { @@ -1897,7 +1783,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) { strncpy(last_file.mime, result[4], sizeof(last_file.mime)-1); /* From what I read, Samsung TV's expect a [wrong] MIME type of x-mkv. */ - if( h->reqflags & FLAG_SAMSUNG ) + if( cflags & FLAG_SAMSUNG ) { if( strcmp(last_file.mime+6, "x-matroska") == 0 ) strcpy(last_file.mime+8, "mkv"); @@ -1955,7 +1841,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Interactive without an image!\n"); /* Samsung TVs (well, at least the A950) do this for some reason, * and I don't see them fixing this bug any time soon. */ - if( !(h->reqflags & FLAG_SAMSUNG) || GETFLAG(DLNA_STRICT_MASK) ) + if( !(cflags & FLAG_SAMSUNG) || GETFLAG(DLNA_STRICT_MASK) ) { Send406(h); goto error; diff --git a/upnphttp.h b/upnphttp.h index e23ef72..8de4499 100644 --- a/upnphttp.h +++ b/upnphttp.h @@ -128,21 +128,6 @@ struct upnphttp { #define FLAG_XFERBACKGROUND 0x00004000 #define FLAG_CAPTION 0x00008000 -#define FLAG_DLNA 0x00100000 -#define FLAG_MIME_AVI_DIVX 0x00200000 -#define FLAG_MIME_AVI_AVI 0x00400000 -#define FLAG_MIME_FLAC_FLAC 0x00800000 -#define FLAG_MIME_WAV_WAV 0x01000000 -#define FLAG_RESIZE_THUMBS 0x02000000 -#define FLAG_NO_RESIZE 0x04000000 -#define FLAG_MS_PFS 0x08000000 // Microsoft PlaysForSure client -#define FLAG_SAMSUNG 0x10000000 -#define FLAG_SAMSUNG_TV 0x20000000 -#define FLAG_AUDIO_ONLY 0x40000000 - -#define FLAG_FREE_OBJECT_ID 0x00000001 -#define FLAG_ROOT_CONTAINER 0x00000002 - #ifndef MSG_MORE #define MSG_MORE 0 #endif @@ -194,9 +179,6 @@ Send501(struct upnphttp *); void SendResp_upnphttp(struct upnphttp *); -int -SearchClientCache(struct in_addr addr, int quiet); - void SendResp_icon(struct upnphttp *, char * url); void diff --git a/upnpsoap.c b/upnpsoap.c index a6fb866..9b53358 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -322,16 +322,17 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action) #define FILTER_PV_SUBTITLE_FILE_URI 0x08000000 #define FILTER_AV_MEDIA_CLASS 0x10000000 -static u_int32_t -set_filter_flags(char * filter, struct upnphttp *h) +static uint32_t +set_filter_flags(char *filter, struct upnphttp *h) { char *item, *saveptr = NULL; uint32_t flags = 0; + int samsung = client_types[h->req_client].flags & FLAG_SAMSUNG; if( !filter || (strlen(filter) <= 1) ) /* Not the full 32 bits. Skip vendor-specific stuff by default. */ return 0xFFFFFF; - if( h->reqflags & FLAG_SAMSUNG ) + if( samsung ) flags |= FILTER_DLNA_NAMESPACE; item = strtok_r(filter, ",", &saveptr); while( item != NULL ) @@ -371,7 +372,7 @@ set_filter_flags(char * filter, struct upnphttp *h) else if( strcmp(item, "upnp:albumArtURI") == 0 ) { flags |= FILTER_UPNP_ALBUMARTURI; - if( h->reqflags & FLAG_SAMSUNG ) + if( samsung ) flags |= FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID; } else if( strcmp(item, "upnp:albumArtURI@dlna:profileID") == 0 ) @@ -1124,8 +1125,8 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) args.returned = 0; args.requested = RequestedCount; - args.client = h->req_client; - args.flags = h->reqflags; + args.client = client_types[h->req_client].type; + args.flags = client_types[h->req_client].flags; args.str = &str; if( args.flags & FLAG_MS_PFS ) { @@ -1201,7 +1202,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) else ret = asprintf(&orderBy, "order by length(OBJECT_ID), OBJECT_ID"); } - else if( args.client == ERokuSoundBridge ) + else if( args.flags & FLAG_FORCE_SORT ) { #ifdef __sparc__ if( totalMatches < 10000 ) @@ -1570,8 +1571,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action) args.returned = 0; args.requested = RequestedCount; - args.client = h->req_client; - args.flags = h->reqflags; + args.client = client_types[h->req_client].type; + args.flags = client_types[h->req_client].flags; args.str = &str; if( args.flags & FLAG_MS_PFS ) { diff --git a/upnpsoap.h b/upnpsoap.h index 484f512..4e027d0 100644 --- a/upnpsoap.h +++ b/upnpsoap.h @@ -33,6 +33,9 @@ #define PV_NAMESPACE \ " xmlns:pv=\"http://www.pv.com/pvns/\"" +#define FLAG_FREE_OBJECT_ID 0x40000000 +#define FLAG_ROOT_CONTAINER 0x80000000 + struct Response { struct string_s *str;