]> git.sesse.net Git - vlc/blobdiff - modules/services_discovery/sap.c
Some compilation fixes when HAVE_LIBCDDB is not defined.
[vlc] / modules / services_discovery / sap.c
index b773acfa347191790621c6af72ba51ffe7753fd6..31966004241dae6eaf095f9f0774906b829f7bca 100644 (file)
  * 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." \
@@ -110,6 +116,8 @@ vlc_module_begin();
                  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 );
 
@@ -246,6 +254,8 @@ static int Open( vlc_object_t *p_this )
 
     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" );
 
@@ -255,8 +265,7 @@ static int Open( vlc_object_t *p_this )
     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" ) )
@@ -270,10 +279,29 @@ static int Open( vlc_object_t *p_this )
     }
     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 )
     {
@@ -293,6 +321,8 @@ static int Open( vlc_object_t *p_this )
     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 );
 
@@ -327,8 +357,6 @@ static int OpenDemux( vlc_object_t *p_this )
         }
     }
 
-    free( p_peek );
-
     p_demux->pf_control = Control;
     p_demux->pf_demux = Demux;
 
@@ -398,6 +426,7 @@ static void Run( services_discovery_t *p_sd )
     /* read SAP packets */
     while( !p_sd->b_die )
     {
+        int i_read;
         p_buffer = (uint8_t *)malloc( MAX_SAP_BUFFER );
 
         if( !p_buffer )
@@ -407,9 +436,9 @@ static void Run( services_discovery_t *p_sd )
             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++ )
@@ -442,8 +471,7 @@ static void Run( services_discovery_t *p_sd )
 
               /* 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 );
 
@@ -484,15 +512,11 @@ static int Demux( demux_t *p_demux )
 
    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 );
 
@@ -517,7 +541,11 @@ static int Demux( demux_t *p_demux )
 
    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 )
    {
@@ -556,10 +584,12 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
  * 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;
@@ -607,14 +637,25 @@ static int ParseSAP( services_discovery_t *p_sd, uint8_t *p_buffer, int i_read )
     }
 
     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 )
@@ -635,12 +676,21 @@ static int ParseSAP( services_discovery_t *p_sd, uint8_t *p_buffer, int i_read )
     }
 
     /* 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++;
     }
 
@@ -649,7 +699,6 @@ static int ParseSAP( services_discovery_t *p_sd, uint8_t *p_buffer, int i_read )
         psz_sdp++;
     }
 
-
     /* Parse SDP info */
     p_sdp = ParseSDP( VLC_OBJECT(p_sd), psz_sdp );
 
@@ -776,8 +825,7 @@ sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash,
     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;
 }
@@ -968,6 +1016,8 @@ static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp )
 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 )
     {
@@ -976,7 +1026,8 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
 
     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;
     }
 
@@ -987,12 +1038,15 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
     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;
@@ -1008,6 +1062,7 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
         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' )
         {
@@ -1038,13 +1093,29 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
                 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 );
@@ -1073,9 +1144,7 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
             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 )
@@ -1120,6 +1189,12 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
                break;
         }
 
+        if( b_invalid )
+        {
+            FreeSDP( p_sdp );
+            return NULL;
+        }
+
         psz_sdp = psz_eol;
     }
 
@@ -1130,7 +1205,6 @@ static sdp_t *  ParseSDP( vlc_object_t *p_obj, char* psz_sdp )
 /***********************************************************************
  * ismult: returns true if we have a multicast address
  ***********************************************************************/
-
 static int ismult( char *psz_uri )
 {
     char *psz_end;
@@ -1153,16 +1227,15 @@ static int ismult( char *psz_uri )
     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;
     }
 
@@ -1236,6 +1309,10 @@ static void FreeSDP( sdp_t *p_sdp )
     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];
@@ -1254,15 +1331,9 @@ static int RemoveAnnounce( services_discovery_t *p_sd,
     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 )
     {
@@ -1295,8 +1366,7 @@ static vlc_bool_t IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 )
         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 ) &&