Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/azatoth/minidlna.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Maggard <jmaggard@users.sourceforce.net>2012-01-21 05:00:26 +0400
committerJustin Maggard <jmaggard@users.sourceforce.net>2012-01-21 05:00:26 +0400
commitaef9da5c9c188dd3c3b6c70523e4c909af4b2d70 (patch)
tree5ba0b34d7383b738969db3dd23952be28d67a26f
parentf59c447f2677136e9715065b19271d6d740b002c (diff)
* Enhance error checking in some additional places as required by the latest UPnP CTT.
-rw-r--r--NEWS12
-rw-r--r--codelength.h1
-rw-r--r--daemonize.c1
-rw-r--r--getifaddr.c1
-rw-r--r--inotify.c3
-rw-r--r--minidlna.c5
-rw-r--r--minissdp.c75
-rw-r--r--minixml.c1
-rw-r--r--testupnpdescgen.c1
-rw-r--r--upnpdescgen.c1
-rw-r--r--upnpevents.c62
-rw-r--r--upnphttp.c119
-rw-r--r--upnphttp.h5
-rw-r--r--upnpsoap.c74
14 files changed, 230 insertions, 131 deletions
diff --git a/NEWS b/NEWS
index d8275a3..3093c3f 100644
--- a/NEWS
+++ b/NEWS
@@ -2,9 +2,21 @@
--------------------------------
- Add support for other operating systems.
- Switch to autoconf from our little genconfig.sh.
+
+1.0.23 - Released 00-Month-0000
+--------------------------------
- Enable the subtitle menu on some Samsung TV's.
- Add subtitle support for Panasonic TV's.
- Add workarounds for LifeTab tablets' bad behavior.
+- Speed up playlist parsing.
+- Make metadata-based virtual containers case insensitive.
+- Add folder art support (very few clients support this though).
+- Improve trimming of quotation marks.
+- Fix SRT caption support with the latest Samsung Series D firmware.
+- Fix subtitles on LG TV's for items whose titles don't have a dot in them.
+- Add support for the av:mediaClass tag, so some Sony devices can filter items by media type.
+- Fix inotify detection issues on first-level folders.
+- Work around LifeTab's broken DLNA support.
1.0.22 - Released 24-Aug-2011
--------------------------------
diff --git a/codelength.h b/codelength.h
index dcb6868..3e298a4 100644
--- a/codelength.h
+++ b/codelength.h
@@ -1,4 +1,3 @@
-/* $Id$ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2008 Thomas Bernard
diff --git a/daemonize.c b/daemonize.c
index 944f8f1..7873d32 100644
--- a/daemonize.c
+++ b/daemonize.c
@@ -1,4 +1,3 @@
-/* $Id$ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*
diff --git a/getifaddr.c b/getifaddr.c
index 4d159a3..f5c2e08 100644
--- a/getifaddr.c
+++ b/getifaddr.c
@@ -1,4 +1,3 @@
-/* $Id$ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*
diff --git a/inotify.c b/inotify.c
index 6d524ec..5dc0962 100644
--- a/inotify.c
+++ b/inotify.c
@@ -156,7 +156,7 @@ inotify_create_watches(int fd)
add_watch(fd, media_path->path);
num_watches++;
}
- sql_get_table(db, "SELECT PATH from DETAILS where SIZE is NULL and PATH is not NULL", &result, &rows, NULL);
+ sql_get_table(db, "SELECT PATH from DETAILS where MIME is NULL and PATH is not NULL", &result, &rows, NULL);
for( i=1; i <= rows; i++ )
{
DPRINTF(E_DEBUG, L_INOTIFY, "Add watch to %s\n", result[i]);
@@ -646,6 +646,7 @@ start_inotify()
inotify_create_watches(pollfds[0].fd);
if (setpriority(PRIO_PROCESS, 0, 19) == -1)
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce inotify thread priority\n");
+ sqlite3_release_memory(1<<31);
while( !quitting )
{
diff --git a/minidlna.c b/minidlna.c
index db757d3..5e3f0a1 100644
--- a/minidlna.c
+++ b/minidlna.c
@@ -825,13 +825,8 @@ init(int argc, char * * argv)
}
else
{
-#ifdef READYNAS
- snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
- "http://%s/admin/", lan_addr[0].str);
-#else
snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
"http://%s:%d/", lan_addr[0].str, runtime_vars.port);
-#endif
}
/* set signal handler */
diff --git a/minissdp.c b/minissdp.c
index 320711b..f5a8c19 100644
--- a/minissdp.c
+++ b/minissdp.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -650,12 +651,12 @@ ProcessSSDPRequest(int s, unsigned short port)
}
else if( !man || (strncmp(man, "\"ssdp:discover\"", 15) != 0) )
{
- DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MAN header %.*s]\n",
- inet_ntoa(sendername.sin_addr), man_len, man);
+ DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
+ inet_ntoa(sendername.sin_addr), "MAN", man_len, man);
}
else if( !mx || mx == mx_end || mx_val < 0 ) {
- DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MX header %.*s]\n",
- inet_ntoa(sendername.sin_addr), mx_len, mx);
+ DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
+ inet_ntoa(sendername.sin_addr), "MX", mx_len, mx);
}
else if( st && (st_len > 0) )
{
@@ -685,11 +686,26 @@ ProcessSSDPRequest(int s, unsigned short port)
for(i = 0; known_service_types[i]; i++)
{
l = strlen(known_service_types[i]);
- if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
+ if( l <= st_len && (memcmp(st, known_service_types[i], l) == 0))
{
- /* Check version number - must always be 1 currently. */
- if( (st[st_len-2] == ':') && (atoi(st+st_len-1) != 1) )
- break;
+ if( st_len != l )
+ {
+ /* Check version number - must always be 1 currently. */
+ if( (st[l-1] == ':') && (st[l] == '1') )
+ l++;
+ while( l < st_len )
+ {
+ if( !isspace(st[l]) )
+ {
+ DPRINTF(E_DEBUG, L_SSDP, "Ignoring SSDP M-SEARCH with bad extra data [%s]\n",
+ inet_ntoa(sendername.sin_addr));
+ break;
+ }
+ l++;
+ }
+ if( l != st_len )
+ break;
+ }
_usleep(random()>>20);
SendSSDPAnnounce2(s, sendername,
i,
@@ -731,6 +747,7 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
struct sockaddr_in sockname;
int n, l;
int i, j;
+ int dup, ret = 0;
char bufr[512];
memset(&sockname, 0, sizeof(struct sockaddr_in));
@@ -738,31 +755,35 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
sockname.sin_port = htons(SSDP_PORT);
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
- for(j=0; j<n_sockets; j++)
+ for (dup = 0; dup < 2; dup++)
{
- for(i=0; known_service_types[i]; i++)
+ for(j=0; j<n_sockets; j++)
{
- l = snprintf(bufr, sizeof(bufr),
- "NOTIFY * HTTP/1.1\r\n"
- "HOST:%s:%d\r\n"
- "NT:%s%s\r\n"
- "USN:%s%s%s%s\r\n"
- "NTS:ssdp:byebye\r\n"
- "\r\n",
- SSDP_MCAST_ADDR, SSDP_PORT,
- known_service_types[i], (i>1?"1":""),
- uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") );
- //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr);
- n = sendto(sockets[j], bufr, l, 0,
- (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
- if(n < 0)
+ for(i=0; known_service_types[i]; i++)
{
- DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno));
- return -1;
+ l = snprintf(bufr, sizeof(bufr),
+ "NOTIFY * HTTP/1.1\r\n"
+ "HOST:%s:%d\r\n"
+ "NT:%s%s\r\n"
+ "USN:%s%s%s%s\r\n"
+ "NTS:ssdp:byebye\r\n"
+ "\r\n",
+ SSDP_MCAST_ADDR, SSDP_PORT,
+ known_service_types[i], (i>1?"1":""),
+ uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") );
+ //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr);
+ n = sendto(sockets[j], bufr, l, 0,
+ (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
+ if(n < 0)
+ {
+ DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno));
+ ret = -1;
+ break;
+ }
}
}
}
- return 0;
+ return ret;
}
/* SubmitServicesToMiniSSDPD() :
diff --git a/minixml.c b/minixml.c
index b335b68..3dfb9a2 100644
--- a/minixml.c
+++ b/minixml.c
@@ -1,4 +1,3 @@
-/* $Id$ */
/* minixml.c : the minimum size a xml parser can be ! */
/* Project : miniupnp
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
diff --git a/testupnpdescgen.c b/testupnpdescgen.c
index 398d731..5d88443 100644
--- a/testupnpdescgen.c
+++ b/testupnpdescgen.c
@@ -1,4 +1,3 @@
-/* $Id$ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*
diff --git a/upnpdescgen.c b/upnpdescgen.c
index c9a40f6..e251412 100644
--- a/upnpdescgen.c
+++ b/upnpdescgen.c
@@ -1,4 +1,3 @@
-/* $Id$ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
*
diff --git a/upnpevents.c b/upnpevents.c
index 895819d..6ce931b 100644
--- a/upnpevents.c
+++ b/upnpevents.c
@@ -54,6 +54,7 @@
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -73,7 +74,6 @@ struct subscriber {
struct upnp_event_notify * notify;
time_t timeout;
uint32_t seq;
- /*enum { EWanCFG = 1, EWanIPC, EL3F } service;*/
enum subscriber_service_enum service;
char uuid[42];
char callback[];
@@ -147,12 +147,8 @@ upnpevents_addSubscriber(const char * eventurl,
int timeout)
{
struct subscriber * tmp;
- /*static char uuid[42];*/
- /* "uuid:00000000-0000-0000-0000-000000000000"; 5+36+1=42bytes */
DPRINTF(E_DEBUG, L_HTTP, "addSubscriber(%s, %.*s, %d)\n",
eventurl, callbacklen, callback, timeout);
- /*strncpy(uuid, uuidvalue, sizeof(uuid));
- uuid[sizeof(uuid)-1] = '\0';*/
tmp = newSubscriber(eventurl, callback, callbacklen);
if(!tmp)
return NULL;
@@ -198,8 +194,7 @@ upnpevents_removeSubscriber(const char * sid, int sidlen)
return -1;
}
-/* notifies all subscriber of a number of port mapping change
- * or external ip address change */
+/* notifies all subscribers of a SystemUpdateID change */
void
upnp_event_var_change_notify(enum subscriber_service_enum service)
{
@@ -265,7 +260,7 @@ upnp_event_notify_connect(struct upnp_event_notify * obj)
}
p = obj->sub->callback;
p += 7; /* http:// */
- while(*p != '/' && *p != ':')
+ while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1))
obj->addrstr[i++] = *(p++);
obj->addrstr[i] = '\0';
if(*p == ':') {
@@ -349,16 +344,15 @@ static void upnp_event_send(struct upnp_event_notify * obj)
{
int i;
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event:\n%s", obj->buffer+obj->sent);
- i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
- if(i<0) {
- DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_send", strerror(errno));
- obj->state = EError;
- return;
+ while( obj->sent < obj->tosend ) {
+ i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
+ if(i<0) {
+ DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_send", strerror(errno));
+ obj->state = EError;
+ return;
+ }
+ obj->sent += i;
}
- else if(i != (obj->tosend - obj->sent))
- DPRINTF(E_WARN, L_HTTP, "%s: %d bytes send out of %d\n",
- "upnp_event_send", i, obj->tosend - obj->sent);
- obj->sent += i;
if(obj->sent == obj->tosend)
obj->state = EWaitingForResponse;
}
@@ -376,7 +370,11 @@ static void upnp_event_recv(struct upnp_event_notify * obj)
n, n, obj->buffer);
obj->state = EFinished;
if(obj->sub)
+ {
obj->sub->seq++;
+ if (!obj->sub->seq)
+ obj->sub->seq++;
+ }
}
static void
@@ -421,13 +419,13 @@ void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd)
if(obj->s > *max_fd)
*max_fd = obj->s;
break;
- case EFinished:
- case EError:
case EWaitingForResponse:
FD_SET(obj->s, readset);
if(obj->s > *max_fd)
*max_fd = obj->s;
break;
+ default:
+ break;
}
}
}
@@ -483,29 +481,3 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset)
}
}
-#ifdef USE_MINIDLNACTL
-void write_events_details(int s) {
- int n;
- char buff[80];
- struct upnp_event_notify * obj;
- struct subscriber * sub;
- write(s, "Events details\n", 15);
- for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
- n = snprintf(buff, sizeof(buff), " %p sub=%p state=%d s=%d\n",
- obj, obj->sub, obj->state, obj->s);
- write(s, buff, n);
- }
- write(s, "Subscribers :\n", 14);
- for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
- n = snprintf(buff, sizeof(buff), " %p timeout=%d seq=%u service=%d\n",
- sub, sub->timeout, sub->seq, sub->service);
- write(s, buff, n);
- n = snprintf(buff, sizeof(buff), " notify=%p %s\n",
- sub->notify, sub->uuid);
- write(s, buff, n);
- n = snprintf(buff, sizeof(buff), " %s\n",
- sub->callback);
- write(s, buff, n);
- }
-}
-#endif
diff --git a/upnphttp.c b/upnphttp.c
index 4e46548..c3c0626 100644
--- a/upnphttp.c
+++ b/upnphttp.c
@@ -209,6 +209,9 @@ ParseHttpHeaders(struct upnphttp * h)
n++;
h->req_Callback = p + 1;
h->req_CallbackLen = MAX(0, n - 1);
+ /* Verify callback validity */
+ if(strncmp(h->req_Callback, "http://", 7) != 0)
+ h->req_Callback = NULL;
}
else if(strncasecmp(line, "SID", 3)==0)
{
@@ -233,6 +236,17 @@ ParseHttpHeaders(struct upnphttp * h)
h->req_SIDLen = n;
}
}
+ else if(strncasecmp(line, "NT", 2)==0)
+ {
+ p = colon + 1;
+ while(isspace(*p))
+ p++;
+ n = 0;
+ while(!isspace(p[n]))
+ n++;
+ h->req_NT = p;
+ h->req_NTLen = n;
+ }
/* Timeout: Seconds-nnnn */
/* TIMEOUT
Recommended. Requested duration until subscription expires,
@@ -406,6 +420,10 @@ intervening space) by either an integer or the keyword "infinite". */
h->reqflags |= FLAG_CHUNKED;
}
}
+ else if(strncasecmp(line, "Accept-Language", 15)==0)
+ {
+ h->reqflags |= FLAG_LANGUAGE;
+ }
else if(strncasecmp(line, "getcontentFeatures.dlna.org", 27)==0)
{
p = colon + 1;
@@ -651,6 +669,34 @@ sendXMLdesc(struct upnphttp * h, char * (f)(int *))
free(desc);
}
+static void
+SendResp_presentation(struct upnphttp * h)
+{
+ char body[1024];
+ int l;
+ h->respflags = FLAG_HTML;
+
+#ifdef READYNAS
+ l = snprintf(body, sizeof(body), "<meta http-equiv=\"refresh\" content=\"0; url=https://%s/admin/\">",
+ lan_addr[h->iface].str);
+#else
+ int a, v, p;
+ a = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'a*'");
+ v = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'v*'");
+ p = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'i*'");
+ l = snprintf(body, sizeof(body),
+ "<HTML><HEAD><TITLE>" SERVER_NAME "</TITLE></HEAD>"
+ "<BODY><div style=\"text-align: center\">"
+ "<h3>" SERVER_NAME " status</h3>"
+ "Audio files: %d<br>"
+ "Video files: %d<br>"
+ "Image files: %d</div>"
+ "</BODY></HTML>\r\n", a, v, p);
+#endif
+ BuildResp_upnphttp(h, body, l);
+ SendResp_upnphttp(h);
+}
+
/* ProcessHTTPPOST_upnphttp()
* executes the SOAP query if it is possible */
static void
@@ -693,7 +739,15 @@ ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n",
h->req_CallbackLen, h->req_Callback, h->req_Timeout);
DPRINTF(E_DEBUG, L_HTTP, "SID '%.*s'\n", h->req_SIDLen, h->req_SID);
- if(!h->req_Callback && !h->req_SID) {
+ if(!h->req_NT) {
+ static const char err400str[] =
+ "<html><body>Bad request</body></html>";
+ BuildResp2_upnphttp(h, 400, "Bad Request",
+ err400str, sizeof(err400str) - 1);
+ SendResp_upnphttp(h);
+ CloseSocket_upnphttp(h);
+ } else if((!h->req_Callback && !h->req_SID) ||
+ strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) {
/* Missing or invalid CALLBACK : 412 Precondition Failed.
* If CALLBACK header is missing or does not contain a valid HTTP URL,
* the publisher must respond with HTTP error 412 Precondition Failed*/
@@ -944,6 +998,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
SendResp_caption(h, HttpUrl+10);
CloseSocket_upnphttp(h);
}
+ else if(strcmp(HttpUrl, "/") == 0)
+ {
+ SendResp_presentation(h);
+ CloseSocket_upnphttp(h);
+ }
else
{
DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", HttpUrl);
@@ -1047,23 +1106,6 @@ Process_upnphttp(struct upnphttp * h)
}
}
-static const char httpresphead[] =
- "%s %d %s\r\n"
- "Content-Type: %s\r\n"
- "Connection: close\r\n"
- "Content-Length: %d\r\n"
- "Server: " MINIDLNA_SERVER_STRING "\r\n"
-// "Accept-Ranges: bytes\r\n"
- ; /*"\r\n";*/
-/*
- "<?xml version=\"1.0\"?>\n"
- "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
- "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
- "<s:Body>"
-
- "</s:Body>"
- "</s:Envelope>";
-*/
/* with response code and response message
* also allocate enough memory */
@@ -1072,15 +1114,22 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
const char * respmsg,
int bodylen)
{
+ static const char httpresphead[] =
+ "%s %d %s\r\n"
+ "Content-Type: %s\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %d\r\n"
+ "Server: " MINIDLNA_SERVER_STRING "\r\n";
+ time_t curtime = time(NULL);
+ char date[30];
int templen;
if(!h->res_buf)
{
- templen = sizeof(httpresphead) + 192 + bodylen;
+ templen = sizeof(httpresphead) + 256 + bodylen;
h->res_buf = (char *)malloc(templen);
h->res_buf_alloclen = templen;
}
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
- //httpresphead, h->HttpVer,
httpresphead, "HTTP/1.1",
respcode, respmsg,
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
@@ -1098,7 +1147,6 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
"300\r\n");
- //JM DLNA must force to 300 - "infinite\r\n");
}
}
if(h->respflags & FLAG_SID) {
@@ -1106,19 +1154,22 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
h->res_buf_alloclen - h->res_buflen,
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
}
-#if 0 // DLNA
- char szTime[30];
- time_t curtime = time(NULL);
- strftime(szTime, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
+ if(h->reqflags & FLAG_LANGUAGE) {
+ h->res_buflen += snprintf(h->res_buf + h->res_buflen,
+ h->res_buf_alloclen - h->res_buflen,
+ "Content-Language: en\r\n");
+ }
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
- "Date: %s\r\n", szTime);
+ "Date: %s\r\n", date);
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
- "contentFeatures.dlna.org: \r\n");
+ "EXT:\r\n");
+#if 0 // DLNA
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
h->res_buf_alloclen - h->res_buflen,
- "EXT:\r\n");
+ "contentFeatures.dlna.org: \r\n");
#endif
h->res_buf[h->res_buflen++] = '\r';
h->res_buf[h->res_buflen++] = '\n';
@@ -1339,8 +1390,6 @@ SendResp_albumArt(struct upnphttp * h, char * object)
}
DPRINTF(E_INFO, L_HTTP, "Serving album art ID: %s [%s]\n", object, path);
- strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
-
fd = open(path, O_RDONLY);
if( fd < 0 ) {
DPRINTF(E_ERROR, L_HTTP, "Error opening %s\n", path);
@@ -1352,6 +1401,7 @@ SendResp_albumArt(struct upnphttp * h, char * object)
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %jd\r\n"
@@ -1403,8 +1453,8 @@ SendResp_caption(struct upnphttp * h, char * object)
sqlite3_free(path);
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
- strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
"Content-Type: smi/caption\r\n"
"Content-Length: %jd\r\n"
@@ -1456,7 +1506,6 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
sqlite3_free(path);
return;
}
- strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
l = exif_loader_new();
exif_loader_write_file(l, path);
@@ -1471,6 +1520,7 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
exif_data_unref(ed);
return;
}
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %d\r\n"
@@ -1611,12 +1661,11 @@ SendResp_resizedimg(struct upnphttp * h, char * object)
else if( srcw>>1 >= dstw && srch>>1 >= dsth )
scale = 2;
- strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
-
str.data = header;
str.size = sizeof(header);
str.off = 0;
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
strcatf(&str, "HTTP/1.1 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Connection: close\r\n"
@@ -1816,7 +1865,6 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
}
}
- strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
offset = h->req_RangeStart;
sendfh = open(last_file.path, O_RDONLY);
if( sendfh < 0 ) {
@@ -1900,6 +1948,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
}
}
+ strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
strcatf(&str, "Accept-Ranges: bytes\r\n"
"Connection: close\r\n"
"Date: %s\r\n"
diff --git a/upnphttp.h b/upnphttp.h
index 9fcfc27..64df2a5 100644
--- a/upnphttp.h
+++ b/upnphttp.h
@@ -71,6 +71,8 @@ struct upnphttp {
int req_soapActionLen;
const char * req_Callback; /* For SUBSCRIBE */
int req_CallbackLen;
+ const char * req_NT;
+ int req_NTLen;
int req_Timeout;
const char * req_SID; /* For UNSUBSCRIBE */
int req_SIDLen;
@@ -92,9 +94,10 @@ struct upnphttp {
#define FLAG_SID 0x00000002
#define FLAG_RANGE 0x00000004
#define FLAG_HOST 0x00000008
+#define FLAG_LANGUAGE 0x00000010
+#define FLAG_INVALID_REQ 0x00000040
#define FLAG_HTML 0x00000080
-#define FLAG_INVALID_REQ 0x00000010
#define FLAG_CHUNKED 0x00000100
#define FLAG_TIMESEEK 0x00000200
diff --git a/upnpsoap.c b/upnpsoap.c
index 6e095d1..fb64b8f 100644
--- a/upnpsoap.c
+++ b/upnpsoap.c
@@ -129,11 +129,22 @@ IsAuthorizedValidated(struct upnphttp * h, const char * action)
char body[512];
int bodylen;
+ struct NameValueParserData data;
+ const char * id;
- bodylen = snprintf(body, sizeof(body), resp,
- action, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1",
- 1, action);
- BuildSendAndCloseSoapResp(h, body, bodylen);
+ ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
+ id = GetValueFromNameValueList(&data, "DeviceID");
+ if(id)
+ {
+ bodylen = snprintf(body, sizeof(body), resp,
+ action, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1",
+ 1, action);
+ BuildSendAndCloseSoapResp(h, body, bodylen);
+ }
+ else
+ SoapError(h, 402, "Invalid Args");
+
+ ClearNameValueList(&data);
}
static void
@@ -246,11 +257,32 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
char body[sizeof(resp)+128];
int bodylen;
+ struct NameValueParserData data;
+ const char * id_str;
+ int id;
+ char *endptr;
- bodylen = snprintf(body, sizeof(body), resp,
- action, "urn:schemas-upnp-org:service:ConnectionManager:1",
- action);
- BuildSendAndCloseSoapResp(h, body, bodylen);
+ ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
+ id_str = GetValueFromNameValueList(&data, "ConnectionID");
+ DPRINTF(E_INFO, L_HTTP, "GetCurrentConnectionInfo(%s)\n", id_str);
+ if(id_str)
+ id = strtol(id_str, &endptr, 10);
+ if(!id_str || !id_str[0] || endptr[0] || id != 0)
+ {
+ SoapError(h, 402, "Invalid Args");
+ }
+ else if(id != 0)
+ {
+ SoapError(h, 701, "No such object error");
+ }
+ else
+ {
+ bodylen = snprintf(body, sizeof(body), resp,
+ action, "urn:schemas-upnp-org:service:ConnectionManager:1",
+ action);
+ BuildSendAndCloseSoapResp(h, body, bodylen);
+ }
+ ClearNameValueList(&data);
}
static void
@@ -533,6 +565,12 @@ parse_sort_criteria(char *sortCriteria, int *error)
reverse = 1;
item++;
}
+ else
+ {
+ DPRINTF(E_DEBUG, L_HTTP, "No order specified [%s]\n", item);
+ *error = 1;
+ goto unhandled_order;
+ }
if( strcasecmp(item, "upnp:class") == 0 )
{
strcat(order, "o.CLASS");
@@ -556,7 +594,7 @@ parse_sort_criteria(char *sortCriteria, int *error)
}
else
{
- printf("Unhandled SortCriteria [%s]\n", item);
+ DPRINTF(E_DEBUG, L_HTTP, "Unhandled SortCriteria [%s]\n", item);
*error = 1;
if( i )
{
@@ -1017,6 +1055,10 @@ callback(void *args, int argc, char **argv, char **azColName)
"&lt;dc:title&gt;%s&lt;/dc:title&gt;"
"&lt;upnp:class&gt;object.%s&lt;/upnp:class&gt;",
title, class);
+ if( strcmp(class+10, "storageFolder") == 0 ) {
+ /* TODO: Implement real folder size tracking */
+ ret = strcatf(str, "&lt;upnp:storageUsed&gt;%s&lt;/upnp:storageUsed&gt;", (size ? size : "-1"));
+ }
if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
ret = strcatf(str, "&lt;dc:creator&gt;%s&lt;/dc:creator&gt;", creator);
}
@@ -1087,10 +1129,20 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
if( (ptr = GetValueFromNameValueList(&data, "RequestedCount")) )
RequestedCount = atoi(ptr);
+ if( RequestedCount < 0 )
+ {
+ SoapError(h, 402, "Invalid Args");
+ goto browse_error;
+ }
if( !RequestedCount )
RequestedCount = -1;
if( (ptr = GetValueFromNameValueList(&data, "StartingIndex")) )
StartingIndex = atoi(ptr);
+ if( StartingIndex < 0 )
+ {
+ SoapError(h, 402, "Invalid Args");
+ goto browse_error;
+ }
if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) )
{
SoapError(h, 402, "Invalid Args");
@@ -1098,7 +1150,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
}
if( !ObjectID && !(ObjectID = GetValueFromNameValueList(&data, "ContainerID")) )
{
- SoapError(h, 701, "No such object error");
+ SoapError(h, 402, "Invalid Args");
goto browse_error;
}
@@ -1293,7 +1345,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
{
if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) )
{
- SoapError(h, 701, "No such object error");
+ SoapError(h, 402, "Invalid Args");
goto search_error;
}
}