]> git.sesse.net Git - vlc/blobdiff - modules/misc/sap.c
* src/playlist/* && Makefile.am
[vlc] / modules / misc / sap.c
index 0483a06cbd171bc13f5e20edf747efa709172954..15e0e441de19f6660a13c37adc0aa0460d3c1ce3 100644 (file)
@@ -2,9 +2,11 @@
  * sap.c :  SAP interface module
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: sap.c,v 1.15 2003/06/20 11:42:07 alexis Exp $
+ * $Id: sap.c,v 1.28 2003/10/29 17:32:55 zorglub Exp $
  *
  * Authors: Arnaud Schauly <gitan@via.ecp.fr>
+ *          ClĂ©ment Stenac <zorglub@via.ecp.fr>
+ *          Damien Lucas <nitrox@videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -63,9 +65,9 @@
 #endif
 
 #ifdef UNDER_CE
-#   define close(a) CloseHandle(a);
+#   define close(a) CloseHandle(a)
 #elif defined( WIN32 )
-#   define close(a) closesocket(a);
+#   define close(a) closesocket(a)
 #endif
 
 #include "network.h"
@@ -86,6 +88,7 @@
 
 typedef struct media_descr_t media_descr_t;
 typedef struct sess_descr_t sess_descr_t;
+typedef struct attr_descr_t attr_descr_t;
 
 static int  Activate     ( vlc_object_t * );
 static void Run          ( intf_thread_t *p_intf );
@@ -108,10 +111,19 @@ static void mfield_parse( char *psz_mfield, char **ppsz_proto,
                char **ppsz_port );
 
 static void free_sd( sess_descr_t * );
+
+/* Detect multicast addresses */
 static int  ismult( char * );
 
+/* Our custom structure */
+struct intf_sys_t
+{
+    int i_group;
+};
+
 /* The struct that contains sdp informations */
-struct  sess_descr_t {
+struct  sess_descr_t
+{
     char *psz_version;
     char *psz_origin;
     char *psz_sessionname;
@@ -124,37 +136,50 @@ struct  sess_descr_t {
     char *psz_attribute;
     char *psz_connection;
     int  i_media;
+    int  i_attributes;
     media_descr_t ** pp_media;
+    attr_descr_t ** pp_attributes;
 };
 
 /* All this informations are not useful yet.  */
-struct media_descr_t {
+struct media_descr_t
+{
     char *psz_medianame;
     char *psz_mediaconnection;
 };
 
+struct attr_descr_t
+{
+    char *psz_field;
+    char *psz_value;
+};
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+
+#define SAP_ADDR_TEXT N_("SAP multicast address")
+#define SAP_ADDR_LONGTEXT N_("SAP multicast address")
+#define SAP_IPV4_TEXT N_("IPv4-SAP listening")
+#define SAP_IPV4_LONGTEXT N_("Set this if you want SAP to listen for IPv4 announces")
+#define SAP_IPV6_TEXT N_("IPv6-SAP listening")
+#define SAP_IPV6_LONGTEXT N_("Set this if you want SAP to listen for IPv6 announces")
+#define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
+#define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)")
+
 vlc_module_begin();
     add_category_hint( N_("SAP"), NULL, VLC_TRUE );
         add_string( "sap-addr", NULL, NULL,
-                     "SAP multicast address", "SAP multicast address", VLC_TRUE );
-    
-        add_bool( "no-sap-ipv4", 0 , NULL,
-                     "NO IPv4-SAP listening",
-                     "Set this if you do not want SAP to listen for IPv4 announces",
-                     VLC_TRUE);
+                     SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
+
+        add_bool( "sap-ipv4", 1 , NULL,
+                     SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE);
 
         add_bool( "sap-ipv6", 0 , NULL,
-                   "IPv6-SAP listening", 
-                   "Set this if you want SAP to listen for IPv6 announces",
-                   VLC_TRUE);
+                   SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE);
 
         add_string( "sap-ipv6-scope", "8" , NULL,
-                    "IPv6-SAP scope",
-                    "Sets the scope for IPv6 announces (default is 8)",
-                    VLC_TRUE);
+                    SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
 
     set_description( _("SAP interface") );
     set_capability( "interface", 0 );
@@ -187,42 +212,61 @@ static void Run( intf_thread_t *p_intf )
     char *psz_network = NULL;
     int fd            = - 1;
     int fdv6          = -1;
-    
-    int no_sap_ipv4      = config_GetInt( p_intf, "no-sap-ipv4" );
+
+    int sap_ipv4         = config_GetInt( p_intf, "sap-ipv4" );
     int sap_ipv6         = config_GetInt( p_intf, "sap-ipv6" );
     char *sap_ipv6_scope = config_GetPsz( p_intf, "sap-ipv6-scope" );
-    
+
     char buffer[MAX_SAP_BUFFER + 1];
 
     module_t            *p_network;
     network_socket_t    socket_desc;
+    playlist_t          *p_playlist;
+    playlist_group_t    *p_group;
 
-    if( no_sap_ipv4 == -1 || sap_ipv6 == -1 || sap_ipv6_scope == NULL )
+    if( sap_ipv4 == -1 || sap_ipv6 == -1 || sap_ipv6_scope == NULL )
     {
         msg_Warn( p_intf, "Unable to parse module configuration" );
         return;
     }
-    
+
+
+    p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
+    if( !p_intf->p_sys )
+    {
+        msg_Err( p_intf, "Out of memory !");
+        return VLC_EGENERIC;
+    }
+    /* Create our playlist group */
+    p_playlist =
+          (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                 FIND_ANYWHERE );
+    p_group = playlist_CreateGroup( p_playlist , "SAP" );
+    p_intf->p_sys->i_group = p_group->i_id;
+
+    vlc_object_release( p_playlist );
+
     /* Prepare IPv4 Networking */
-    if ( no_sap_ipv4 == 0)
+    if ( sap_ipv4 == 1)
     {
         if( !(psz_addr = config_GetPsz( p_intf, "sap-addr" ) ) )
-        { 
+        {
             psz_addr = strdup( HELLO_GROUP );
-        } 
-            
+        }
+
         /* Prepare the network_socket_t structure */
         socket_desc.i_type            = NETWORK_UDP;
         socket_desc.psz_bind_addr     = psz_addr;
         socket_desc.i_bind_port       = HELLO_PORT;
         socket_desc.psz_server_addr   = "";
         socket_desc.i_server_port     = 0;
+        socket_desc.i_ttl             = 0;
         p_intf->p_private = (void*) &socket_desc;
 
-        psz_network = "ipv4"; 
+        psz_network = "ipv4";
 
        /* Create, Bind the socket, ... with the appropriate module  */
+
         if( !( p_network = module_Need( p_intf, "network", psz_network ) ) )
         {
             msg_Warn( p_intf, "failed to open a connection (udp)" );
@@ -238,23 +282,29 @@ static void Run( intf_thread_t *p_intf )
     {
         /* Prepare the network_socket_t structure */
 
-        psz_addrv6=(char *)malloc(sizeof(char)*38); 
+        psz_addrv6=(char *)malloc(sizeof(char)*38);
+
+        if( !psz_addrv6)
+        {
+            msg_Warn( p_intf, "Out of memory !" );
+        }
         /* Max size of an IPv6 address */
-        
+
         sprintf(psz_addrv6,"[%s%c%s]",IPV6_ADDR_1,
                         sap_ipv6_scope[0],IPV6_ADDR_2);
-        
+
         socket_desc.i_type            = NETWORK_UDP;
         socket_desc.psz_bind_addr     = psz_addrv6;
         socket_desc.i_bind_port       = HELLO_PORT;
         socket_desc.psz_server_addr   = "";
         socket_desc.i_server_port     = 0;
+        socket_desc.i_ttl             = 0;
         p_intf->p_private = (void*) &socket_desc;
 
-        psz_network = "ipv6"; 
+        psz_network = "ipv6";
 
        /* Create, Bind the socket, ... with the appropriate module  */
+
         if( !( p_network = module_Need( p_intf, "network", psz_network ) ) )
         {
             msg_Warn( p_intf, "failed to open a connection (udp)" );
@@ -265,7 +315,7 @@ static void Run( intf_thread_t *p_intf )
         fdv6 = socket_desc.i_handle;
     }
 
-    
+
     /* read SAP packets */
     while( !p_intf->b_die )
     {
@@ -290,7 +340,20 @@ static void Run( intf_thread_t *p_intf )
     }
 
     /* Closing socket */
-    close( socket_desc.i_handle );
+    if( fd > 0)
+    {
+        if( close( fd ) )
+        {
+            msg_Warn( p_intf, "Ohoh, unable to close the socket" );
+        }
+    }
+    if( fdv6 > 0)
+    {
+        if( close( fdv6 ) )
+        {
+            msg_Warn( p_intf, "Ohoh, unable to close the socket" );
+        }
+    }
 }
 
 /********************************************************************
@@ -321,7 +384,9 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
     char *psz_port;
     char *psz_uri_default;
     int i_multicast;
-    int i_count;
+    int i_count , i;
+    vlc_bool_t b_http = VLC_FALSE;
+    char *psz_http_path = NULL;
     playlist_t *p_playlist;
 
     psz_uri_default = NULL;
@@ -340,6 +405,8 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
         p_item->i_status = 0;
         p_item->b_autodeletion = VLC_FALSE;
         p_item->psz_uri = NULL;
+        p_item->ppsz_options = NULL;
+        p_item->i_options = 0;
 
         psz_uri = NULL;
 
@@ -374,34 +441,73 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
             return 0;
         }
 
+        for( i = 0 ; i< p_sd->i_attributes ; i++ )
+        {
+            if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "type") &&
+                strstr( p_sd->pp_attributes[i]->psz_value, "http") )
+            {
+                b_http = VLC_TRUE;
+            }
+            if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path"))
+            {
+                psz_http_path = strdup(  p_sd->pp_attributes[i]->psz_value );
+
+            }
+        }
+
 
         /* Filling p_item->psz_uri */
-        i_multicast = ismult( psz_uri );
+        if( b_http == VLC_FALSE )
+        {
+            i_multicast = ismult( psz_uri );
 
-        p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
+            p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
                         strlen( psz_port ) + 5 +i_multicast );
-        if( p_item->psz_uri == NULL )
-        {
-            msg_Err( p_intf, "Not enough memory");
-            free( p_item );
-            return 0;
-        }
 
-        if( i_multicast == 1)
-        {
-            sprintf( p_item->psz_uri, "%s://@%s:%s", psz_proto,
+            if( p_item->psz_uri == NULL )
+            {
+                msg_Err( p_intf, "Not enough memory");
+                free( p_item );
+                return 0;
+            }
+
+            if( i_multicast == 1)
+            {
+                sprintf( p_item->psz_uri, "%s://@%s:%s", psz_proto,
+                                 psz_uri, psz_port );
+            }
+            else
+            {
+                sprintf( p_item->psz_uri, "%s://%s:%s", psz_proto,
                             psz_uri, psz_port );
+            }
         }
         else
         {
-            sprintf( p_item->psz_uri, "%s://%s:%s", psz_proto,
-                            psz_uri, psz_port );
-        }
+            if( psz_http_path == NULL )
+                psz_http_path = strdup("/");
+
+            p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
+                        strlen( psz_port ) + 3 + strlen(psz_http_path) );
+
+            if( p_item->psz_uri == NULL )
+            {
+                msg_Err( p_intf, "Not enough memory");
+                free( p_item );
+                return 0;
+            }
+
+            sprintf( p_item->psz_uri, "%s://%s:%s%s", psz_proto,
+                            psz_uri, psz_port,psz_http_path );
 
-        /* Enqueueing p_item in the playlist */
+        }
+            /* Enqueueing p_item in the playlist */
 
         if( p_item )
         {
+            p_item->i_group = p_intf->p_sys->i_group;
+            p_item->b_enabled = VLC_TRUE;
+            p_item->psz_author = NULL;
             p_playlist = vlc_object_find( p_intf,
             VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
 
@@ -410,10 +516,10 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
             vlc_object_release( p_playlist );
         }
 
-
+        if( psz_http_path )
+            free(psz_http_path);
     }
 
-
     return 1;
 
 }
@@ -529,6 +635,14 @@ static int parse_sap( char *p_packet )
     //Looks for the first '\0' byte after length
     for(;p_packet[i_hlen]!='\0'; i_hlen++);
 
+    if( i_hlen > 50 ) /* Definitely too long...
+                         Maybe we have a fucked up packet without  \0 */
+    {   /* As a workaround, we search for "v=" */
+        i_hlen = 4;
+        for(;p_packet[i_hlen] != 'v' && p_packet[i_hlen+1] != '=' ; i_hlen++);
+        return i_hlen-1;
+    }
+
     return(i_hlen);
 }
 
@@ -570,7 +684,9 @@ static int packet_handle( intf_thread_t * p_intf, char *p_packet, int i_len )
 static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
 {
     sess_descr_t *  sd;
+    char *psz_eof;
 
+    unsigned int i;
     // According to RFC 2327, the first bytes should be exactly "v="
     if((p_packet[0] != 'v') || (p_packet[1] != '='))
     {
@@ -585,6 +701,7 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
     }
 
     sd->pp_media = NULL;
+    sd->pp_attributes = NULL;
     sd->psz_origin = NULL;
     sd->psz_sessionname = NULL;
     sd->psz_information = NULL;
@@ -596,7 +713,9 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
     sd->psz_attribute = NULL;
     sd->psz_connection = NULL;
 
-    sd->i_media = 0;
+
+    sd->i_media      = 0;
+    sd->i_attributes = 0;
 
     while( *p_packet != '\0'  )
     {
@@ -653,7 +772,57 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
                     FIELD_COPY( sd->psz_repeat );
                     break;
                 case( 'a' ):
-                    FIELD_COPY( sd->psz_attribute );
+                    if( sd->pp_attributes )
+                    {
+                        sd->pp_attributes =
+                            realloc( sd->pp_attributes,
+                                    sizeof( attr_descr_t ) *
+                                    ( sd->i_attributes +1 ) );
+                    }
+                    else
+                    {
+                        sd->pp_attributes = malloc( sizeof( void * ) );
+                    }
+                    if( !sd->pp_attributes )
+                    {
+                        msg_Warn( p_intf, "Out of memory !" );
+                        return NULL;
+                    }
+                    sd->pp_attributes[sd->i_attributes] =
+                            malloc( sizeof( attr_descr_t ) );
+                    if( ! sd->pp_attributes[sd->i_attributes])
+                    {
+                        msg_Warn( p_intf, "Out of memory !" );
+                        return NULL;
+                    }
+
+                    p_packet += 2;
+                    psz_eof = strchr( p_packet, ':');
+                    if(psz_eof)
+                        *psz_eof = '\0';
+                    sd->pp_attributes[sd->i_attributes]->psz_field =
+                            strdup( p_packet );
+                    if( psz_eof + 1 )
+                    {
+                        sd->pp_attributes[sd->i_attributes]->psz_value =
+                            strdup( ++psz_eof );
+                    }
+                    else
+                    {
+                        if( sd->pp_attributes[sd->i_attributes]->psz_field )
+                            free( sd->pp_attributes[sd->i_attributes]
+                                              ->psz_field );
+                        break;
+                    }
+                    for( i=0 ; i<
+                      strlen(sd->pp_attributes[sd->i_attributes]->psz_value) ;
+                             i++ )
+                    {
+                        if(sd->pp_attributes[sd->i_attributes]->psz_value[i]
+                                        =='\n' )
+                          sd->pp_attributes[sd->i_attributes]->psz_value[i]                                            =0;
+                    }
+                    sd->i_attributes++;
                     break;
 
                 case( 'm' ):
@@ -667,12 +836,17 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
                     {
                         sd->pp_media = malloc( sizeof( void * ) );
                     }
-
+                    if( !sd->pp_media )
+                    {
+                        msg_Warn( p_intf, "Out of memory !" );
+                        return NULL;
+                    }
                     sd->pp_media[sd->i_media] =
                             malloc( sizeof( media_descr_t ) );
                     sd->pp_media[sd->i_media]->psz_medianame = NULL;
                     sd->pp_media[sd->i_media]->psz_mediaconnection = NULL;
-                    sd->pp_media[sd->i_media]->psz_medianame = strndup( &p_packet[2], i_field_len );
+                    sd->pp_media[sd->i_media]->psz_medianame =
+                                   strndup( &p_packet[2], i_field_len );
 
                     sd->i_media++;
                     break;
@@ -721,6 +895,12 @@ static void free_sd( sess_descr_t * p_sd )
             FREE( p_sd->pp_media[i]->psz_medianame );
             FREE( p_sd->pp_media[i]->psz_mediaconnection );
         }
+        for( i = 0; i < p_sd->i_attributes ; i++ )
+        {
+            FREE( p_sd->pp_attributes[i]->psz_field );
+            FREE( p_sd->pp_attributes[i]->psz_value );
+        }
+        FREE( p_sd->pp_attributes );
         FREE( p_sd->pp_media );
 
         free( p_sd );
@@ -743,21 +923,30 @@ static int ismult( char *psz_uri )
 
     i_value = strtol( psz_uri, &psz_end, 0 );
 
-    /* FIXME: This is an ugly way to detect IPv6 multicast */
-    if( psz_uri[0] == '[') { return( VLC_TRUE ); } 
+    /* IPv6 */
+    if( psz_uri[0] == '[')
+    {
+      if( strncasecmp( &psz_uri[1], "FF0" , 3) ||
+          strncasecmp( &psz_uri[2], "FF0" , 3))
+            return( VLC_TRUE );
+        else
+            return( VLC_FALSE );
+    }
 
     if( *psz_end != '.' ) { return( VLC_FALSE ); }
 
     return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
 }
 
+
+
 /*****************************************************************************
  * Read: read on a file descriptor, checking b_die periodically
  *****************************************************************************
  * Taken from udp.c
  ******************************************************************************/
 static ssize_t NetRead( intf_thread_t *p_intf,
-                        int i_handle, int i_handle_v6, 
+                        int i_handle, int i_handle_v6,
                         byte_t *p_buffer, size_t i_len)
 {
 #ifdef UNDER_CE
@@ -770,14 +959,14 @@ static ssize_t NetRead( intf_thread_t *p_intf,
     int             i_max_handle;
 
     ssize_t i_recv=-1;
-    
+
     /* Get the max handle for select */
     if( i_handle_v6 > i_handle )
         i_max_handle = i_handle_v6;
     else
         i_max_handle = i_handle;
 
-    
+
     /* Initialize file descriptor set */
     FD_ZERO( &fds );
     if(   i_handle > 0   ) FD_SET( i_handle, &fds );
@@ -798,7 +987,7 @@ static ssize_t NetRead( intf_thread_t *p_intf,
     }
     else if( i_ret > 0 )
    {
-      /* Get the data */     
+      /* Get the data */
       if(i_handle >0)
       {
          if(FD_ISSET( i_handle, &fds ))
@@ -813,7 +1002,7 @@ static ssize_t NetRead( intf_thread_t *p_intf,
             i_recv = recv( i_handle_v6, p_buffer, i_len, 0 );
          }
       }
-      
+
        if( i_recv < 0 )
         {
            msg_Err( p_intf, "recv failed (%s)", strerror(errno) );