diff --git a/minidlna.c b/minidlna.c index cc1286e..a119c99 100644 --- a/minidlna.c +++ b/minidlna.c @@ -66,6 +66,9 @@ OpenAndConfHTTPSocket(unsigned short port) int i = 1; struct sockaddr_in listenname; + /* Initialize client type cache */ + memset(&clients, 0, sizeof(struct client_cache_s)); + if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { DPRINTF(E_ERROR, L_GENERAL, "socket(http): %s\n", strerror(errno)); diff --git a/minidlnatypes.h b/minidlnatypes.h index b249774..9f8434a 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -28,6 +28,12 @@ enum media_types { IMAGES_ONLY }; +enum client_types { + EXbox = 1, + EPS3, + ESamsungTV +}; + struct media_dir_s { char * path; /* Base path */ enum media_types type; /* type of files to scan */ @@ -39,4 +45,10 @@ struct album_art_name_s { struct album_art_name_s * next; }; +struct client_cache_s { + struct in_addr addr; + enum client_types type; + time_t age; +}; + #endif diff --git a/upnpglobalvars.c b/upnpglobalvars.c index 27e16ff..c13f2c6 100644 --- a/upnpglobalvars.c +++ b/upnpglobalvars.c @@ -39,5 +39,6 @@ sqlite3 * db; char friendly_name[FRIENDLYNAME_MAX_LEN]; struct media_dir_s * media_dirs = NULL; struct album_art_name_s * album_art_names = NULL; +struct client_cache_s clients[CLIENT_CACHE_SLOTS]; short int scanning = 0; volatile __u32 updateID = 0; diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 955871c..f3b9c11 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -15,6 +15,7 @@ #include +#define CLIENT_CACHE_SLOTS 20 #define USE_FORK 1 #define DB_VERSION 1 @@ -91,6 +92,7 @@ extern sqlite3 *db; extern char friendly_name[]; 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 short int scanning; extern volatile __u32 updateID; diff --git a/upnphttp.c b/upnphttp.c index 36e2443..fa1d953 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -86,6 +86,27 @@ Delete_upnphttp(struct upnphttp * h) } } +int +SearchClientCache(struct in_addr addr) +{ + int i; + for( i=0; i 7200 ) + { + memset(&clients[i], 0, sizeof(struct client_cache_s)); + return -1; + } + DPRINTF(E_DEBUG, L_HTTP, "Client [%d] found in cache.\n", clients[i].type); + return i; + } + } + return -1; +} + /* parse HttpHeaders of the REQUEST */ static void ParseHttpHeaders(struct upnphttp * h) @@ -191,6 +212,14 @@ intervening space) by either an integer or the keyword "infinite". */ { h->req_client = EXbox; } + else if(strncmp(p, "PLAYSTATION", 11)==0) + { + h->req_client = EPS3; + } + else if(strncmp(p, "SamsungWiselinkPro", 18)==0) + { + h->req_client = ESamsungTV; + } } else if(strncasecmp(line, "Transfer-Encoding", 17)==0) { @@ -262,6 +291,32 @@ intervening space) by either an integer or the keyword "infinite". */ h->req_chunklen = -1; } } + /* If the client type wasn't found, search the cache. + * This is done because a lot of clients like to send a + * different User-Agent with different types of requests. */ + n = SearchClientCache(h->clientaddr); + if( h->req_client ) + { + /* Add this client to the cache if it's not there already. */ + if( n < 0 ) + { + for( n=0; nclientaddr; + clients[n].type = h->req_client; + DPRINTF(E_DEBUG, L_HTTP, "Added client [%d/%X] to cache slot %d.\n", + clients[n].type, clients[n].addr.s_addr, n); + break; + } + } + clients[n].age = time(NULL); + } + else if( n >= 0 ) + { + h->req_client = clients[n].type; + } } /* very minimalistic 400 error message */ @@ -1366,14 +1421,17 @@ SendResp_dlnafile(struct upnphttp * h, char * object) Send400(h); goto error; } -#if 1 // Some Samsung TVs do this? if( strncmp(last_file.mime, "image", 5) != 0 ) { DPRINTF(E_WARN, L_HTTP, "Client tried to specify transferMode as Interactive without an image!\n"); - Send406(h); - goto error; + /* 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->req_client != ESamsungTV ) + { + Send406(h); + goto error; + } } -#endif } strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime)); diff --git a/upnphttp.h b/upnphttp.h index f2bb35c..efbc9fd 100644 --- a/upnphttp.h +++ b/upnphttp.h @@ -10,6 +10,7 @@ #include #include +#include "minidlnatypes.h" #include "config.h" /* server: HTTP header returned in all HTTP responses : */ @@ -31,10 +32,6 @@ enum httpCommands { EUnSubscribe }; -enum clientType { - EXbox = 1 -}; - struct upnphttp { int socket; struct in_addr clientaddr; /* client address */ @@ -46,7 +43,7 @@ struct upnphttp { int req_contentlen; int req_contentoff; /* header length */ enum httpCommands req_command; - enum clientType req_client; + enum client_types req_client; const char * req_soapAction; int req_soapActionLen; const char * req_Callback; /* For SUBSCRIBE */ diff --git a/upnpsoap.h b/upnpsoap.h index 2af832e..af33ccd 100644 --- a/upnpsoap.h +++ b/upnpsoap.h @@ -22,7 +22,7 @@ struct Response int requested; int size; u_int32_t filter; - enum clientType client; + enum client_types client; }; /* ExecuteSoapAction():