From c10c913b3096a7dbadedda2c38181ed4a4ea33d4 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Tue, 19 May 2009 23:43:51 +0000 Subject: [PATCH] * Some fixes for the UPnP Device Validator. --- minidlna.c | 2 +- minissdp.c | 57 +++++++++++++++++------------------------ tagutils/tagutils-wav.c | 2 ++ upnpdescgen.c | 18 +++++++------ upnpevents.c | 14 +++++++--- upnphttp.c | 5 ++-- upnpsoap.c | 8 +++++- 7 files changed, 58 insertions(+), 48 deletions(-) diff --git a/minidlna.c b/minidlna.c index 3c2371d..c26a7dc 100644 --- a/minidlna.c +++ b/minidlna.c @@ -246,7 +246,7 @@ init(int argc, char * * argv) if( (getifhwaddr("eth0", mac_str, 64) < 0) && (getifhwaddr("eth1", mac_str, 64) < 0) ) { - printf("No MAC addresses found!\n"); + DPRINTF(E_WARN, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n"); strcpy(mac_str, "554e4b4e4f57"); } strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-"); diff --git a/minissdp.c b/minissdp.c index 92b82da..5a5e73a 100644 --- a/minissdp.c +++ b/minissdp.c @@ -188,11 +188,21 @@ USN:uuid:upnp-InternetGatewayDevice-1_0-0090a2777777::upnp:rootdevice EXT: */ +static const char * const known_service_types[] = +{ + uuidvalue, + "upnp:rootdevice", + "urn:schemas-upnp-org:device:MediaServer:", + "urn:schemas-upnp-org:service:ContentDirectory:", + "urn:schemas-upnp-org:service:ConnectionManager:", + "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:", + 0 +}; + /* not really an SSDP "announce" as it is the response * to a SSDP "M-SEARCH" */ static void -SendSSDPAnnounce2(int s, struct sockaddr_in sockname, - const char * st, int st_len, const char * suffix, +SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no, const char * host, unsigned short port) { int l, n; @@ -211,18 +221,18 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n" "CACHE-CONTROL: max-age=1810\r\n" "DATE: %s\r\n" - "Ext:\r\n" - "ST: %.*s%s\r\n" - "USN: %s%s%.*s%s\r\n" + "ST: %s%s\r\n" + "USN: %s%s%s%s\r\n" "EXT:\r\n" "SERVER: " MINIDLNA_SERVER_STRING "\r\n" "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n" "Content-Length: 0\r\n" "\r\n", szTime, - st_len, st, suffix, - uuidvalue, st_len?"::":"", st_len, st, suffix, + known_service_types[st_no], (st_no>1?"1":""), + uuidvalue, (st_no>0?"::":""), (st_no>0?known_service_types[st_no]:""), (st_no>1?"1":""), host, (unsigned int)port); + //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending M-SEARCH response:\n%s", buf); n = sendto(s, buf, l, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); if(n < 0) @@ -231,17 +241,6 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, } } -static const char * const known_service_types[] = -{ - uuidvalue, - "upnp:rootdevice", - "urn:schemas-upnp-org:device:MediaServer:", - "urn:schemas-upnp-org:service:ContentDirectory:", - "urn:schemas-upnp-org:service:ConnectionManager:", - "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:", - 0 -}; - static void SendSSDPNotifies(int s, const char * host, unsigned short port, unsigned int lifetime) @@ -282,7 +281,7 @@ SendSSDPNotifies(int s, const char * host, unsigned short port, DPRINTF(E_WARN, L_SSDP, "SendSSDPNotifies(): truncated output\n"); l = sizeof(bufr); } - //DEBUG printf("Sending NOTIFY:\n%s", bufr); + //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr); n = sendto(s, bufr, l, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); if(n < 0) @@ -341,6 +340,7 @@ ProcessSSDPRequest(int s, unsigned short port) } else if(memcmp(bufr, "M-SEARCH", 8) == 0) { + //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Received SSDP request:\n%.*s", n, bufr); for(i=0; i < n; i++) { if( bufr[i] == '*' ) @@ -397,7 +397,6 @@ ProcessSSDPRequest(int s, unsigned short port) } else if( st ) { - /* TODO : doesnt answer at once but wait for a random time */ DPRINTF(E_INFO, L_SSDP, "SSDP M-SEARCH from %s:%d ST: %.*s, MX: %.*s, MAN: %.*s\n", inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port), @@ -421,8 +420,9 @@ ProcessSSDPRequest(int s, unsigned short port) /* Check version number - must always be 1 currently. */ if( (st[st_len-2] == ':') && (atoi(st+st_len-1) != 1) ) break; + usleep(random()>>20); SendSSDPAnnounce2(s, sendername, - st, st_len, "", + i, lan_addr[lan_addr_index].str, port); break; } @@ -431,23 +431,14 @@ ProcessSSDPRequest(int s, unsigned short port) /* strlen("ssdp:all") == 8 */ if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8))) { - SendSSDPAnnounce2(s, sendername, "", 0, "", - lan_addr[lan_addr_index].str, port); - for(i=1; known_service_types[i]; i++) + for(i=0; known_service_types[i]; i++) { l = (int)strlen(known_service_types[i]); SendSSDPAnnounce2(s, sendername, - known_service_types[i], l, i==1?"":"1", + i, lan_addr[lan_addr_index].str, port); } } - /* responds to request by UUID value */ - l = (int)strlen(uuidvalue); - if(l==st_len && (0 == memcmp(st, uuidvalue, l))) - { - SendSSDPAnnounce2(s, sendername, st, st_len, "", - lan_addr[lan_addr_index].str, port); - } } else { @@ -491,7 +482,7 @@ SendSSDPGoodbye(int * sockets, int n_sockets) 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 printf("Sending NOTIFY:\n%s", bufr); + //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) diff --git a/tagutils/tagutils-wav.c b/tagutils/tagutils-wav.c index 6f9f1a5..e881d6e 100644 --- a/tagutils/tagutils-wav.c +++ b/tagutils/tagutils-wav.c @@ -164,7 +164,9 @@ _get_wavtags(char *filename, struct song_metadata *psong) //DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Song length: %d\n", psong->song_length); //DEBUG DPRINTF(E_DEBUG,L_SCANNER,"Bit rate: %d\n", psong->bitrate); +#if 0 // Wrong MIME type? PS3 doesn't like it; it wants audio/x-wav. asprintf(&(psong->mime), "audio/L16;rate=%d;channels=%d", psong->samplerate, psong->channels); +#endif return 0; } diff --git a/upnpdescgen.c b/upnpdescgen.c index 5116f84..4893759 100644 --- a/upnpdescgen.c +++ b/upnpdescgen.c @@ -84,7 +84,9 @@ static const char * const upnpallowedvalues[] = 0, RESOURCE_PROTOCOL_INFO_VALUES, /* 44 */ 0, - "", /* 46 */ + "0", /* 46 */ + 0, + "", /* 48 */ 0 }; @@ -291,8 +293,8 @@ static const struct action ConnectionManagerActions[] = static const struct stateVar ConnectionManagerVars[] = { {"SourceProtocolInfo", 1<<7, 0, 44, 44}, /* required */ - {"SinkProtocolInfo", 1<<7, 0}, /* required */ - {"CurrentConnectionIDs", 1<<7, 0}, /* required */ + {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */ + {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */ {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */ {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */ {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */ @@ -374,7 +376,7 @@ static const struct action ContentDirectoryActions[] = static const struct stateVar ContentDirectoryVars[] = { - {"TransferIDs", 1<<7, 0, 0, 46}, /* 0 */ + {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */ {"A_ARG_TYPE_ObjectID", 0, 0}, {"A_ARG_TYPE_Result", 0, 0}, {"A_ARG_TYPE_SearchCriteria", 0, 0}, @@ -434,10 +436,10 @@ static const struct stateVar X_MS_MediaReceiverRegistrarVars[] = {"A_ARG_TYPE_RegistrationReqMsg", 7, 0}, {"A_ARG_TYPE_RegistrationRespMsg", 7, 0}, {"A_ARG_TYPE_Result", 6, 0}, - {"AuthorizationDeniedUpdateID", (1<<7)|3, 0}, - {"AuthorizationGrantedUpdateID", (1<<7)|3, 0}, - {"ValidationRevokedUpdateID", (1<<7)|3, 0}, - {"ValidationSucceededUpdateID", (1<<7)|3, 0}, + {"AuthorizationDeniedUpdateID", 3, 0}, + {"AuthorizationGrantedUpdateID", 3, 0}, + {"ValidationRevokedUpdateID", 3, 0}, + {"ValidationSucceededUpdateID", 3, 0}, {0, 0} }; diff --git a/upnpevents.c b/upnpevents.c index d140e11..3ec8a4d 100644 --- a/upnpevents.c +++ b/upnpevents.c @@ -150,8 +150,10 @@ upnpevents_removeSubscriber(const char * sid, int sidlen) struct subscriber * sub; if(!sid) return -1; + DPRINTF(E_DEBUG, L_HTTP, "removeSubscriber(%.*s)\n", + sidlen, sid); for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) { - if(memcmp(sid, sub->uuid, 41)) { + if(memcmp(sid, sub->uuid, 41) == 0) { if(sub->notify) { sub->notify->sub = NULL; } @@ -238,7 +240,7 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) i = 1; p++; port = (unsigned short)atoi(p); - while(*p != '/') { + while(*p != '/' && *p != '\0') { if(i<7) obj->portstr[i++] = *p; p++; } @@ -247,7 +249,10 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) port = 80; obj->portstr[0] = '\0'; } - obj->path = p; + if( *p ) + obj->path = p; + else + obj->path = "/"; addr.sin_family = AF_INET; inet_aton(obj->addrstr, &addr.sin_addr); addr.sin_port = htons(port); @@ -313,6 +318,7 @@ static void upnp_event_prepare(struct upnp_event_notify * obj) 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)); @@ -422,11 +428,13 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset) } if(obj->sub) obj->sub->notify = NULL; +#if 0 /* Just let it time out instead of explicitly removing the subscriber */ /* remove also the subscriber from the list if there was an error */ if(obj->state == EError && obj->sub) { LIST_REMOVE(obj->sub, entries); free(obj->sub); } +#endif if(obj->buffer) { free(obj->buffer); } diff --git a/upnphttp.c b/upnphttp.c index 7f973d9..3d6defc 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -555,6 +555,7 @@ with HTTP error 412 Precondition Failed. */ /* A DLNA device must enforce a 5 minute timeout */ h->respflags = FLAG_TIMEOUT; h->req_Timeout = 300; + h->respflags |= FLAG_SID; BuildResp_upnphttp(h, 0, 0); } } @@ -853,7 +854,7 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode, int templen; if(!h->res_buf) { - templen = sizeof(httpresphead) + 128 + bodylen; + templen = sizeof(httpresphead) + 192 + bodylen; h->res_buf = (char *)malloc(templen); h->res_buf_alloclen = templen; } @@ -882,7 +883,7 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode, if(h->respflags & FLAG_SID) { h->res_buflen += snprintf(h->res_buf + h->res_buflen, h->res_buf_alloclen - h->res_buflen, - "SID: %s\r\n", h->req_SID); + "SID: %.*s\r\n", h->req_SIDLen, h->req_SID); } #if 0 // DLNA char szTime[30]; diff --git a/upnpsoap.c b/upnpsoap.c index aa73de8..49b39ea 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -351,37 +351,43 @@ set_filter_flags(char * filter) flags |= FILTER_RES; } else if( (strcmp(item, "res@bitrate") == 0) || + (strcmp(item, "@bitrate") == 0) || ((strcmp(item, "bitrate") == 0) && (flags & FILTER_RES)) ) { flags |= FILTER_RES; flags |= FILTER_RES_BITRATE; } else if( (strcmp(item, "res@duration") == 0) || + (strcmp(item, "@duration") == 0) || ((strcmp(item, "duration") == 0) && (flags & FILTER_RES)) ) { flags |= FILTER_RES; flags |= FILTER_RES_DURATION; } else if( (strcmp(item, "res@nrAudioChannels") == 0) || + (strcmp(item, "@nrAudioChannels") == 0) || ((strcmp(item, "nrAudioChannels") == 0) && (flags & FILTER_RES)) ) { flags |= FILTER_RES; flags |= FILTER_RES_NRAUDIOCHANNELS; } else if( (strcmp(item, "res@resolution") == 0) || + (strcmp(item, "@resolution") == 0) || ((strcmp(item, "resolution") == 0) && (flags & FILTER_RES)) ) { flags |= FILTER_RES; flags |= FILTER_RES_RESOLUTION; } else if( (strcmp(item, "res@sampleFrequency") == 0) || + (strcmp(item, "@sampleFrequency") == 0) || ((strcmp(item, "sampleFrequency") == 0) && (flags & FILTER_RES)) ) { flags |= FILTER_RES; flags |= FILTER_RES_SAMPLEFREQUENCY; } else if( (strcmp(item, "res@size") == 0) || - ((strcmp(item, "size") == 0) && (flags & FILTER_RES)) ) + (strcmp(item, "@size") == 0) || + (strcmp(item, "size") == 0) ) { flags |= FILTER_RES; flags |= FILTER_RES_SIZE;