Workaround for Samsung Smart TV 2012 : - URI patch made by swiergot http://sourceforge.net/tracker/index.php?func=detail&aid=3532724&group_id=129766&atid=715782 - per device content-type engine : change video/x-matroska with video/x-mkv for Samsung devices only --- a/tombupnp/upnp/src/genlib/miniserver/miniserver.c +++ b/tombupnp/upnp/src/genlib/miniserver/miniserver.c @@ -842,6 +842,8 @@ return UPNP_E_INTERNAL_ERROR; // miniserver running } + ssdpdevices_init(&GlobalSsdpDevices); + miniSocket = ( MiniServerSockArray * ) malloc( sizeof( MiniServerSockArray ) ); if( miniSocket == NULL ) @@ -963,5 +965,8 @@ } shutdown( sock, SD_BOTH ); UpnpCloseSocket( sock ); + + ssdpdevices_destroy(&GlobalSsdpDevices); + return 0; } --- a/tombupnp/upnp/src/genlib/net/http/webserver.c +++ b/tombupnp/upnp/src/genlib/net/http/webserver.c @@ -1211,6 +1211,7 @@ * * Parameters: * IN http_message_t *req ; HTTP Request message +* IN SOCKINFO *info ; Socket info (fd with remote ip & port) * OUT enum resp_type *rtype ; Tpye of response * OUT membuffer *headers ; * OUT membuffer *filename ; Get filename from request document @@ -1230,6 +1231,7 @@ ************************************************************************/ static int process_request( IN http_message_t * req, + IN SOCKINFO *info, OUT enum resp_type *rtype, OUT membuffer * headers, OUT membuffer * filename, @@ -1473,6 +1475,19 @@ goto error_handler; } + // change "x-matroska" by "x-mkv", for samsung devices only + char *newtype; + if((strcmp(finfo.content_type, "video/x-matroska")==0)) { + if(ssdpdevice_servermatch(&GlobalSsdpDevices, info->foreign_ip_addr.s_addr, "samsung")) { +// printf("Req from Samsung device : %s\n", finfo.content_type); + // change is made in two steps : free the previous string, malloc a new one + if((newtype= (char *) strdup("video/x-mkv"))) { + free(finfo.content_type); + finfo.content_type = newtype; + } + } + } + if( RespInstr->IsRangeActive && RespInstr->IsChunkActive ) { //Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT //Transfer-Encoding: chunked @@ -1800,7 +1815,7 @@ //Process request should create the different kind of header depending on the //the type of request. ret = - process_request( req, &rtype, &headers, &filename, &xmldoc, + process_request( req, info, &rtype, &headers, &filename, &xmldoc, &RespInstr, &Fp); if( ret != UPNP_E_SUCCESS ) { // send error code --- a/tombupnp/upnp/src/genlib/net/uri/uri.c +++ b/tombupnp/upnp/src/genlib/net/uri/uri.c @@ -1042,7 +1042,8 @@ out->path_type = REL_PATH; } - if( ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' ) + //parse hostport only if scheme was found + if( ( begin_hostport > 0 ) && ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' ) && ( in[begin_hostport + 1] == '/' ) ) { begin_hostport += 2; @@ -1059,6 +1060,12 @@ out->hostport.text.size = 0; out->hostport.text.buff = 0; begin_path = begin_hostport; + + //remove excessive leading slashes (fix for Samsung Smart TV 2012) + while( ( ( begin_path + 1 ) < max ) && ( in[begin_path] == '/' ) && ( in[begin_path + 1] == '/') ) { + begin_path++; + } + } begin_fragment = --- a/tombupnp/upnp/src/inc/ssdplib.h +++ b/tombupnp/upnp/src/inc/ssdplib.h @@ -161,9 +161,22 @@ struct sockaddr_in dest_addr; } ssdp_thread_data; +typedef struct +{ + ithread_mutex_t mutex; + LinkedList deviceslist; +} ssdpdevices_t; + +typedef struct +{ + uint32_t s_addr; + char *serverdesc; +} ssdp_device_t; /* globals */ +extern ssdpdevices_t GlobalSsdpDevices; + CLIENTONLY(extern SOCKET gSsdpReqSocket;); typedef int (*ParserFun)(char *, Event *); @@ -174,6 +187,64 @@ //int AnalyzeCommand(char * szCommand, Event * Evt); /************************************************************************ +* Function : ssdpdevices_free +* +* Parameters : +* void *d ; +* +* Description : Free memory allocated for each SSDP Device +* +* Return : void ; +* +* Note : +************************************************************************/ +void ssdpdevice_free( void *d ); + +/************************************************************************ +* Function : ssdpdevice_compare +* +* Parameters : +* void* param1 ; +* void* param2 ; +* +* Description : Compare two SSDP devices by their ip address +* +* Return : int ; +* +* Note : +************************************************************************/ +int ssdpdevice_compare( void *param1, void *param2 ); + +/************************************************************************ +* Function : ssdpdevices_init +* +* Parameters : +* INOUT ssdpdevices_t* s ; Array of SSDP Devices +* +* Description : Initialize and allocate memory for the array of SSDP devices +* +* Return : void ; +* +* Note : +************************************************************************/ + +void ssdpdevices_init(ssdpdevices_t* s); + +/************************************************************************ +* Function : ssdpdevices_destroy +* +* Parameters : +* INOUT ssdpdevices_t* msg ; Array of SSDP Devices +* +* Description : Free memory allocated for the Array of SSDP Devices +* +* Return : void ; +* +* Note : +************************************************************************/ +void ssdpdevices_destroy( ssdpdevices_t *s ); + +/************************************************************************ * Function : Make_Socket_NoBlocking * * Parameters: --- a/tombupnp/upnp/src/ssdp/ssdp_server.c +++ b/tombupnp/upnp/src/ssdp/ssdp_server.c @@ -52,8 +52,231 @@ #include "unixutil.h" #endif +#include + #define MAX_TIME_TOREAD 45 +// global containing the array of devices +ssdpdevices_t GlobalSsdpDevices; + +/************************************************************************ +* Function : ssdpdevices_free +* +* Parameters : +* void *msg ; +* +* Description : Free memory allocated for each SSDP Device +* +* Return : void ; +* +* Note : +************************************************************************/ +void +ssdpdevice_free( void *d ) +{ + ssdp_device_t *sd = ( ssdp_device_t * ) d; + + free(sd->serverdesc); + + free( sd ); +} + +/************************************************************************ +* Function : ssdpdevice_compare +* +* Parameters : +* void* param1 ; +* void* param2 ; +* +* Description : Compare two SSDP devices by their ip address +* +* Return : int ; +* +* Note : +************************************************************************/ +int +ssdpdevice_compare( void *param1, + void *param2 ) +{ + assert( param1 != NULL ); + assert( param2 != NULL ); + + return ( ( ssdp_device_t * ) param1 )->s_addr == + ( ( ssdp_device_t * ) param2 )->s_addr; +} + +/************************************************************************ +* Function : ssdpdevices_init +* +* Parameters : +* INOUT ssdpdevices_t* s ; Array of SSDP Devices +* +* Description : Initialize and allocate memory for the array of SSDP devices +* +* Return : void ; +* +* Note : +************************************************************************/ + +void ssdpdevices_init(ssdpdevices_t* s) { + ithread_mutex_init( &s->mutex, NULL ); + ListInit( &s->deviceslist, ssdpdevice_compare, ssdpdevice_free ); +} + +/************************************************************************ +* Function : ssdpdevices_destroy +* +* Parameters : +* INOUT ssdpdevices_t* s ; Array of SSDP Devices +* +* Description : Free memory allocated for the Array of SSDP Devices +* +* Return : void ; +* +* Note : +************************************************************************/ +void +ssdpdevices_destroy( ssdpdevices_t *s ) +{ + int ret; + + assert( s != NULL ); + + ithread_mutex_lock( &s->mutex ); + ListDestroy( &s->deviceslist, 1 ); + ithread_mutex_unlock( &s->mutex ); + + ret = ithread_mutex_destroy( &s->mutex ); + assert( ret == 0 ); + +} + +/************************************************************************ +* Function : create_device_node +* +* Parameters : +* IN uint32_t *ip4addr; IP Address +* IN membuffer *mbuf; Server descripton +* +* Description : Create a device structure and fill it with ip & description +* +* Return : ssdp_device_t * +* +* Note : +************************************************************************/ + +ssdp_device_t *create_device(uint32_t ipaddr, membuffer *mbuf) { + ssdp_device_t *newd; + if( (newd = (ssdp_device_t *) malloc(sizeof(ssdp_device_t)))) { + if( ( newd->serverdesc = str_alloc ( mbuf->buf, mbuf->length) ) ) { + newd->s_addr = ipaddr; + return(newd); + } + free(newd); + } + return(NULL); +} + + +/************************************************************************ +* Function : ssdpdevices_updatelist +* +* Parameters : +* INOUT ssdpdevices_t* s ; Array of SSDP Devices +* IN uint32_t *ip4addr; IP Address +* IN char *serverstr; Server descripton +* +* Description : Insert or update the list with given device +* +* Return : void ; +* +* Note : +************************************************************************/ +void +ssdpdevices_updatelist( ssdpdevices_t *s, uint32_t ip4addr, membuffer *serverstr) +{ + assert( s != NULL ); + assert( ip4addr != 0 ); + assert( serverstr != NULL ); + + int found = 0; + + // Loop through each existing device + ithread_mutex_lock( &s->mutex ); + LinkedList *l = &s->deviceslist; + ListNode *temp = NULL; + ssdp_device_t *d,*newd; + for (temp = ListHead(l);temp!=NULL;temp = ListNext(l,temp)) + { + d=(ssdp_device_t *)temp->item; + if(d->s_addr == ip4addr) { + found = 1; + break; + } + } + + // Add the entry if necessary + if(!found) { + if( ( newd = create_device(ip4addr, serverstr))) { + ListAddTail( l, newd); + } + } + ithread_mutex_unlock( &s->mutex ); + +} + +/************************************************************************ +* Function : ssdpdevice_descmatch +* +* Parameters : +* IN ssdpdevices_t* s ; Array of SSDP Devices +* IN uint32_t ipaddr; Ip addres to check +* IN char *regexp; Regex to match +* +* Description : Check whether the device's description matches the given regex +* +* Return : int (1 = match, else no match) +* +* Note : +************************************************************************/ +int +ssdpdevice_servermatch( ssdpdevices_t *s, uint32_t ip4addr, char *regex) +{ + assert( s != NULL ); + assert( ip4addr != 0 ); + assert( regex != NULL ); + + int ret = 0; + regex_t reg; + + if( regcomp(®, regex, REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) { + printf("Invalid regex : %s\n", regex); + return(0); + } + + // Loop through each existing device + ithread_mutex_lock( &s->mutex ); + LinkedList *l = &s->deviceslist; + ListNode *temp = NULL; + ssdp_device_t *d; + for (temp = ListHead(l);temp!=NULL;temp = ListNext(l,temp)) + { + d=(ssdp_device_t *)temp->item; + if(d->s_addr == ip4addr) { + // We found the ip addr, let's check if the desc contains the searched string + if(regexec(®, d->serverdesc, 0, NULL, 0) == 0) { + ret=1; + } + break; + } + } + + ithread_mutex_unlock( &s->mutex ); + return(ret); +} + + + CLIENTONLY( SOCKET gSsdpReqSocket = 0; ) @@ -756,6 +979,24 @@ if( !valid_ssdp_msg( &parser->msg ) ) { goto error_handler; } + + // update liste of devices for each NOTIFY received + + if ( parser->msg.method == HTTPMETHOD_NOTIFY ) { +// printf( "SSDP recvd code NOTIFY = %d from %s\n", parser->msg.method, inet_ntoa(data->dest_addr.sin_addr)); + LinkedList *g=&parser->msg.headers; + ListNode *temp = NULL; + http_header_t *h; + for (temp = ListHead(g);temp!=NULL;temp = ListNext(g,temp)) + { + h=(http_header_t *)temp->item; + if(strncasecmp(h->name.buf, "SERVER", h->name.length) == 0) { + ssdpdevices_updatelist(&GlobalSsdpDevices, data->dest_addr.sin_addr.s_addr, &h->value); + } + } + + } + return 0; //////// done; thread will free 'data' error_handler: