* Module descriptor
*****************************************************************************/
#define SAP_ADDR_TEXT N_( "SAP multicast address" )
-#define SAP_ADDR_LONGTEXT N_( "SAP multicast address" )
+#define SAP_ADDR_LONGTEXT N_( "Listen for SAP announces on another address" )
#define SAP_IPV4_TEXT N_( "IPv4-SAP listening" )
#define SAP_IPV4_LONGTEXT N_( \
- "Set this if you want the SAP module to listen to IPv4 announces" )
+ "Set this if you want the SAP module to listen to IPv4 announces " \
+ "on the standard address" )
#define SAP_IPV6_TEXT N_( "IPv6-SAP listening" )
#define SAP_IPV6_LONGTEXT N_( \
- "Set this if you want the SAP module to listen to IPv6 announces" )
+ "Set this if you want the SAP module to listen to IPv6 announces " \
+ "on the standard address" )
#define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )
#define SAP_SCOPE_LONGTEXT N_( \
"Sets the scope for IPv6 announces (default is 8)" )
#define SAP_PARSE_LONGTEXT N_( \
"When SAP can it will try to parse the SAP. If you don't select " \
"this, all announces will be parsed by the livedotcom module" )
+#define SAP_STRICT_TEXT N_( "SAP Strict mode" )
+#define SAP_STRICT_LONGTEXT N_( \
+ "When this is set, the SAP parser will discard some non-compliant " \
+ "announces" )
#define SAP_CACHE_TEXT N_("Use SAP cache")
#define SAP_CACHE_LONGTEXT N_( \
"If this option is selected, a SAP caching mechanism will be used." \
SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, VLC_TRUE );
add_bool( "sap-parse", 1 , NULL,
SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, VLC_TRUE );
+ add_bool( "sap-strict", 0 , NULL,
+ SAP_STRICT_TEXT,SAP_STRICT_LONGTEXT, VLC_TRUE );
add_bool( "sap-cache", 0 , NULL,
SAP_CACHE_TEXT,SAP_CACHE_LONGTEXT, VLC_TRUE );
playlist_t *p_playlist;
playlist_view_t *p_view;
+ char *psz_addr;
+ vlc_value_t val;
p_sys->i_timeout = config_GetInt( p_sd,"sap-timeout" );
p_sys->pi_fd = NULL;
p_sys->i_fd = 0;
- /* FIXME */
- p_sys->b_strict = VLC_FALSE;
+ p_sys->b_strict = config_GetInt( p_sd, "sap-strict");
p_sys->b_parse = config_GetInt( p_sd, "sap-parse" );
if( config_GetInt( p_sd, "sap-cache" ) )
}
if( config_GetInt( p_sd, "sap-ipv6" ) )
{
- /* TODO */
+ /* [ + 8x4+7*':' + ] */
+ char psz_address[42];
+ char c_scope;
+ char *psz_scope = config_GetPsz( p_sd, "sap-ipv6-scope" );
+
+ if( psz_scope == NULL || *psz_scope == '\0')
+ {
+ c_scope = '8';
+ }
+ else
+ {
+ c_scope = psz_scope[0];
+ }
+ snprintf( psz_address, 42, "[%s%c%s]", IPV6_ADDR_1, c_scope,
+ IPV6_ADDR_2 );
+ InitSocket( p_sd, psz_address, SAP_PORT );
}
- /* TODO : Handle additionnal adresses */
+ psz_addr = config_GetPsz( p_sd, "sap-addr" );
+ if( psz_addr && *psz_addr )
+ {
+ InitSocket( p_sd, psz_addr, SAP_PORT );
+ }
if( p_sys->i_fd == 0 )
{
p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY );
p_sys->p_node = playlist_NodeCreate( p_playlist, VIEW_CATEGORY,
_("SAP"), p_view->p_root );
+ val.b_bool = VLC_TRUE;
+ var_Set( p_playlist, "intf-change", val );
vlc_object_release( p_playlist );
}
}
- free( p_peek );
-
p_demux->pf_control = Control;
p_demux->pf_demux = Demux;
/* read SAP packets */
while( !p_sd->b_die )
{
+ int i_read;
p_buffer = (uint8_t *)malloc( MAX_SAP_BUFFER );
if( !p_buffer )
continue;
}
- int i_read = net_Select( p_sd, p_sd->p_sys->pi_fd, NULL,
- p_sd->p_sys->i_fd, p_buffer,
- MAX_SAP_BUFFER, 500000 );
+ i_read = net_Select( p_sd, p_sd->p_sys->pi_fd, NULL,
+ p_sd->p_sys->i_fd, p_buffer,
+ MAX_SAP_BUFFER, 500000 );
#if 0
/* Check for items that need deletion */
for( i = 0 ; i< p_sd->p_sys->i_announces ; i++ )
/* Remove the sap_announce from the array */
REMOVE_ELEM( p_sd->p_sys->pp_announces,
- p_sd->p_sys->i_announces,
- i );
+ p_sd->p_sys->i_announces, i );
free( p_announce );
playlist_t *p_playlist;
- if( !psz_sdp )
- {
- return -1;
- }
+ if( !psz_sdp ) return -1;
/* Gather the complete sdp file */
for( ;; )
{
- fprintf(stderr,"read %i at %p\n",i_max_sdp - i_sdp - 1, &psz_sdp[i_sdp]);
int i_read = stream_Read( p_demux->s,
&psz_sdp[i_sdp], i_max_sdp - i_sdp - 1 );
p_sdp = ParseSDP( VLC_OBJECT(p_demux), psz_sdp );
- if( !p_sdp ) return -1;
+ if( !p_sdp )
+ {
+ msg_Warn( p_demux, "invalid SDP");
+ return -1;
+ }
if( p_sdp->i_media > 1 )
{
* Local functions
**************************************************************/
+/* i_read is at least > 6 */
static int ParseSAP( services_discovery_t *p_sd, uint8_t *p_buffer, int i_read )
{
int i_version, i_address_type, i_hash, i;
uint8_t *psz_sdp;
+ uint8_t *psz_initial_sdp;
sdp_t *p_sdp;
vlc_bool_t b_compressed;
vlc_bool_t b_need_delete = VLC_FALSE;
}
psz_sdp = &p_buffer[4];
+ psz_initial_sdp = psz_sdp;
if( i_address_type == 0 ) /* ipv4 source address */
{
psz_sdp += 4;
+ if( i_read <= 9 )
+ {
+ msg_Warn( p_sd,"too short SAP packet\n" );
+ return VLC_EGENERIC;
+ }
}
else /* ipv6 source address */
{
psz_sdp += 16;
+ if( i_read <= 21 )
+ {
+ msg_Warn( p_sd,"too short SAP packet\n" );
+ return VLC_EGENERIC;
+ }
}
if( b_compressed )
}
/* Add the size of authentification info */
+ if( i_read < p_buffer[1] + (psz_sdp - psz_initial_sdp ) )
+ {
+ msg_Warn( p_sd, "too short SAP packet\n");
+ return VLC_EGENERIC;
+ }
psz_sdp += p_buffer[1];
/* Skip payload type */
/* Handle announces without \0 between SAP and SDP */
while( *psz_sdp != '\0' && ( psz_sdp[0] != 'v' && psz_sdp[1] != '=' ) )
{
+ if( psz_sdp - psz_initial_sdp >= i_read - 5 )
+ {
+ msg_Warn( p_sd, "empty SDP ?");
+ }
psz_sdp++;
}
psz_sdp++;
}
-
/* Parse SDP info */
p_sdp = ParseSDP( VLC_OBJECT(p_sd), psz_sdp );
p_sap->p_item = p_item;
TAB_APPEND( p_sd->p_sys->i_announces,
- p_sd->p_sys->pp_announces,
- p_sap );
+ p_sd->p_sys->pp_announces, p_sap );
return p_sap;
}
static sdp_t * ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
{
sdp_t *p_sdp;
+ vlc_bool_t b_invalid = VLC_FALSE;
+ vlc_bool_t b_end = VLC_FALSE;
if( psz_sdp == NULL )
{
if( psz_sdp[0] != 'v' || psz_sdp[1] != '=' )
{
- msg_Warn( p_obj, "bad SDP packet" );
+ msg_Warn( p_obj, "bad SDP packet, begins with 0x%x(%c) 0x%x(%c)",
+ psz_sdp[0],psz_sdp[0],psz_sdp[1],psz_sdp[1]);
return NULL;
}
p_sdp->psz_sessionname = NULL;
p_sdp->psz_media = NULL;
p_sdp->psz_connection = NULL;
+ p_sdp->psz_uri = NULL;
+ p_sdp->psz_address = NULL;
+ p_sdp->psz_address_type= NULL;
p_sdp->i_media = 0;
p_sdp->i_attributes = 0;
p_sdp->pp_attributes = NULL;
- while( *psz_sdp != '\0' )
+ while( *psz_sdp != '\0' && b_end == VLC_FALSE )
{
char *psz_eol;
char *psz_eof;
if( ( psz_eol = strchr( psz_sdp, '\n' ) ) == NULL )
{
psz_eol = psz_sdp + strlen( psz_sdp );
+ b_end = VLC_TRUE;
}
if( psz_eol > psz_sdp && *( psz_eol - 1 ) == '\r' )
{
break;
case ( 'o' ):
{
+ int i_field = 0;
/* o field is <username> <session id> <version>
* <network type> <address type> <address> */
-#define GET_FIELD( store ) \
+#define GET_FIELD( store ) \
psz_eof = strchr( psz_parse, ' ' ); \
- if( psz_eof ) { *psz_eof=0; store = strdup( psz_parse ); } \
- else { store = strdup( psz_parse );}; psz_parse = psz_eof + 1 ;
+ if( psz_eof ) \
+ { \
+ *psz_eof=0; store = strdup( psz_parse ); \
+ } \
+ else \
+ { \
+ if( i_field != 5 ) \
+ { \
+ b_invalid = VLC_TRUE; break; \
+ } \
+ else \
+ { \
+ store = strdup( psz_parse ); \
+ } \
+ }; \
+ psz_parse = psz_eof + 1; i_field++;
+
psz_parse = &psz_sdp[2];
GET_FIELD( p_sdp->psz_username );
case( 'a' ): /* attribute */
{
char *psz_eon = strchr( &psz_sdp[2], ':' );
-
- attribute_t *p_attr = (attribute_t *)malloc(
- sizeof( attribute_t ) );
+ attribute_t *p_attr = malloc( sizeof( attribute_t ) );
/* Attribute with value */
if( psz_eon )
break;
}
+ if( b_invalid )
+ {
+ FreeSDP( p_sdp );
+ return NULL;
+ }
+
psz_sdp = psz_eol;
}
/***********************************************************************
* ismult: returns true if we have a multicast address
***********************************************************************/
-
static int ismult( char *psz_uri )
{
char *psz_end;
return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
}
-static int InitSocket( services_discovery_t *p_sd, char *psz_address, int i_port )
+static int InitSocket( services_discovery_t *p_sd, char *psz_address,
+ int i_port )
{
int i_fd = net_OpenUDP( p_sd, psz_address, i_port, "", 0 );
if( i_fd != -1 )
{
- INSERT_ELEM( p_sd->p_sys->pi_fd,
- p_sd->p_sys->i_fd,
- p_sd->p_sys->i_fd,
- i_fd );
+ INSERT_ELEM( p_sd->p_sys->pi_fd, p_sd->p_sys->i_fd,
+ p_sd->p_sys->i_fd, i_fd );
return VLC_SUCCESS;
}
FREE( p_sdp->psz_connection );
FREE( p_sdp->psz_media );
FREE( p_sdp->psz_uri );
+
+ FREE( p_sdp->psz_address );
+ FREE( p_sdp->psz_address_type );
+
for( i= p_sdp->i_attributes - 1; i >= 0 ; i-- )
{
struct attribute_t *p_attr = p_sdp->pp_attributes[i];
playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_sd,
VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
- if( p_announce->p_sdp )
- {
- FreeSDP( p_announce->p_sdp );
- }
+ if( p_announce->p_sdp ) FreeSDP( p_announce->p_sdp );
- if( !p_playlist )
- {
- return VLC_EGENERIC;
- }
+ if( !p_playlist ) return VLC_EGENERIC;
if( p_announce->p_item )
{
p_sdp1->psz_address_type && p_sdp2->psz_address_type &&
p_sdp1->psz_address && p_sdp2->psz_address )
{
- if(
- !strcmp( p_sdp1->psz_username , p_sdp2->psz_username ) &&
+ if(!strcmp( p_sdp1->psz_username , p_sdp2->psz_username ) &&
!strcmp( p_sdp1->psz_network_type , p_sdp2->psz_network_type ) &&
!strcmp( p_sdp1->psz_address_type , p_sdp2->psz_address_type ) &&
!strcmp( p_sdp1->psz_address , p_sdp2->psz_address ) &&