]> git.sesse.net Git - vlc/blobdiff - modules/misc/sap.c
- Updated French translation (still a lot of work to do...)
[vlc] / modules / misc / sap.c
index 52417ca02d023b08c8b100ae2f48ac7607dad3e2..075f5f0519246f82a6dab878d61ac42d1a1af06a 100644 (file)
@@ -2,7 +2,7 @@
  * sap.c :  SAP interface module
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: sap.c,v 1.31 2003/11/06 09:59:45 gbazin Exp $
+ * $Id: sap.c,v 1.39 2003/11/23 18:31:54 alexis Exp $
  *
  * Authors: Arnaud Schauly <gitan@via.ecp.fr>
  *          ClĂ©ment Stenac <zorglub@via.ecp.fr>
 
 #include "network.h"
 
+#ifdef HAVE_ZLIB_H
+#   include <zlib.h>
+#endif
+
 #define MAX_LINE_LENGTH 256
 
 /* SAP is always on that port */
@@ -83,9 +87,9 @@
 #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_IPV4_LONGTEXT N_("Set this if you want the SAP module to listen to 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_IPV6_LONGTEXT N_("Set this if you want the SAP module to listen to IPv6 announces")
 #define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
 #define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)")
 
@@ -136,6 +140,7 @@ struct  sess_descr_t
     int  i_version;
     char *psz_sessionname;
     char *psz_connection;
+    char *psz_sdp;
 
     int           i_media;
     media_descr_t **pp_media;
@@ -165,6 +170,47 @@ struct intf_sys_t
     int i_group;
 };
 
+#ifdef HAVE_ZLIB_H
+int do_decompress(unsigned char *src, unsigned char **_dst, int slen) {
+  int result, dstsize, n;
+  unsigned char *dst;
+  z_stream d_stream;
+
+  d_stream.zalloc = (alloc_func)0;
+  d_stream.zfree = (free_func)0;
+  d_stream.opaque = (voidpf)0;
+  result = inflateInit(&d_stream);
+  if (result != Z_OK) {
+    printf("inflateInit() failed. Result: %d\n", result);
+    return(-1);
+  }
+
+  d_stream.next_in = (Bytef *)src;
+  d_stream.avail_in = slen;
+  n = 0;
+  dst = NULL;
+  do {
+    n++;
+    dst = (unsigned char *)realloc(dst, n * 1000);
+    d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
+    d_stream.avail_out = 1000;
+    result = inflate(&d_stream, Z_NO_FLUSH);
+    if ((result != Z_OK) && (result != Z_STREAM_END)) {
+      printf("Zlib decompression failed. Result: %d\n", result);
+      return(-1);
+    }
+  } while ((d_stream.avail_out == 0) && (d_stream.avail_in != 0) &&
+           (result != Z_STREAM_END));
+
+  dstsize = d_stream.total_out;
+  inflateEnd(&d_stream);
+
+  *_dst = (unsigned char *)realloc(dst, dstsize);
+
+  return dstsize;
+}
+#endif
+
 /*****************************************************************************
  * Open: initialize and create stuff
  *****************************************************************************/
@@ -290,19 +336,29 @@ static void Close( vlc_object_t *p_this )
  *****************************************************************************
  * Listens to SAP packets, and sends them to packet_handle
  *****************************************************************************/
-#define MAX_SAP_BUFFER 2000
+#define MAX_SAP_BUFFER 5000
 
 static void Run( intf_thread_t *p_intf )
 {
     intf_sys_t *p_sys  = p_intf->p_sys;
     uint8_t     buffer[MAX_SAP_BUFFER + 1];
+    uint8_t    *p_end;
 
     /* read SAP packets */
     while( !p_intf->b_die )
     {
         int i_read = NetRead( p_intf, p_sys->fd, buffer, MAX_SAP_BUFFER );
         uint8_t *p_sdp;
-
+        int i_version;
+        int i_address_type;
+        int b_reserved;
+        int b_message_type;
+        int b_encrypted;
+        int b_compressed;
+        int i_mesg_id_hash;
+        unsigned char *p_decompressed_buffer;
+        int i_decompressed_size;
+        
         /* Minimum length is > 6 */
         if( i_read <= 6 )
         {
@@ -314,13 +370,57 @@ static void Run( intf_thread_t *p_intf )
         }
 
         buffer[i_read] = '\0';
+        p_end = &buffer[i_read];
 
         /* Parse the SAP header */
+        i_version = buffer[0] >> 5;
+        if( i_version != 1 )
+        {
+            msg_Warn( p_intf, "strange sap version %d found", i_version );
+        }
+        i_address_type = buffer[0] & 0x10;
+        b_reserved = buffer[0] & 0x08;
+        if( b_reserved != 0 )
+        {
+            msg_Warn( p_intf, "reserved bit incorrectly set" );
+        }
+        b_message_type = buffer[0] & 0x04;
+        if( b_message_type != 0 )
+        {
+            msg_Warn( p_intf, "got session deletion packet" );
+        }
+        b_encrypted = buffer[0] & 0x02;
+        if( b_encrypted )
+        {
+            msg_Warn( p_intf, "encrypted packet" );
+        }
+        b_compressed = buffer[0] & 0x01;
         p_sdp  = &buffer[4];
-        p_sdp += (buffer[0]&0x10) ? 16 : 4;
-        p_sdp += buffer[1];
-
-        while( p_sdp < &buffer[i_read-1] && *p_sdp != '\0' && p_sdp[0] != 'v' && p_sdp[1] != '=' )
+        if( i_address_type == 0 ) /* ipv4 source address */
+        {
+            p_sdp += 4;
+        }
+        else /* ipv6 source address */
+        {
+            p_sdp += 16;
+        }
+        if( b_compressed )
+        {
+#ifdef HAVE_ZLIB_H
+            i_decompressed_size = do_decompress( p_sdp, &p_decompressed_buffer, i_read - ( p_sdp - buffer ) );
+            if( i_decompressed_size > 0 && i_decompressed_size < MAX_SAP_BUFFER )
+            {
+                memcpy( p_sdp, p_decompressed_buffer, i_decompressed_size );
+                p_sdp[i_decompressed_size] = '\0';
+                p_end = &p_sdp[i_decompressed_size];
+                free( p_decompressed_buffer );
+            }
+#else
+            msg_Warn( p_intf, "Ignoring compressed sap packet" );
+#endif
+        }
+        p_sdp += buffer[1]; /* size of signature */
+        while( p_sdp < p_end - 1 && *p_sdp != '\0' && p_sdp[0] != 'v' && p_sdp[1] != '=' )
         {
             p_sdp++;
         }
@@ -328,7 +428,8 @@ static void Run( intf_thread_t *p_intf )
         {
             p_sdp++;
         }
-        if( p_sdp < &buffer[i_read] )
+
+        if( p_sdp < p_end )
         {
             sess_descr_t *p_sd = parse_sdp( p_intf, p_sdp );
             if( p_sd )
@@ -337,6 +438,10 @@ static void Run( intf_thread_t *p_intf )
                 free_sd ( p_sd );
             }
         }
+        else
+        {
+            msg_Warn( p_intf, "ditching sap packet" );
+        }
     }
 }
 
@@ -393,16 +498,28 @@ static void mfield_parse( char *psz_mfield, char **ppsz_proto,
                char **ppsz_port )
 {
     char *psz_pos;
+    char *psz_media;
     if( psz_mfield )
     {
         psz_pos = psz_mfield;
+        psz_media = psz_mfield;
         while( *psz_pos != '\0' && *psz_pos != ' ' )
         {
             psz_pos++;
         }
+        if( *psz_pos != '\0' )
+        {
+            *psz_pos = '\0';
+            if( strcmp( psz_media, "video" ) && strcmp( psz_media, "audio" ) )
+            {
+                *ppsz_proto = NULL;
+                *ppsz_port = NULL;
+                return;
+            }
+        }
         psz_pos++;
         *ppsz_port = psz_pos;
-        while( *psz_pos != '\0' && *psz_pos && *psz_pos !=' ' && *psz_pos!='/' )
+        while( *psz_pos != '\0' && *psz_pos !=' ' && *psz_pos!='/' )
         {
             psz_pos++;
         }
@@ -452,9 +569,49 @@ static void sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
     int i_count , i;
     vlc_bool_t b_http = VLC_FALSE;
     char *psz_http_path = NULL;
-    playlist_t *p_playlist;
+    playlist_t *p_playlist = NULL;
 
     psz_uri_default = NULL;
+    if( p_sd->i_media > 1 )
+    {
+        p_item = malloc( sizeof( playlist_item_t ) );
+        if( p_item == NULL )
+        {
+            msg_Warn( p_intf, "out of memory" );
+            return;
+        }
+        p_item->psz_name    = strdup( p_sd->psz_sessionname );
+        p_item->psz_uri     = NULL;
+        p_item->i_duration  = -1;
+        p_item->ppsz_options= NULL;
+        p_item->i_options   = 0;
+
+        p_item->i_type      = 0;
+        p_item->i_status    = 0;
+        p_item->b_autodeletion = VLC_FALSE;
+        p_item->b_enabled   = VLC_TRUE;
+        p_item->i_group     = p_intf->p_sys->i_group;
+        p_item->psz_author  = strdup( "" );
+        psz_uri = malloc( strlen( p_sd->psz_sdp ) + 7 );
+        if( psz_uri == NULL )
+        {
+            msg_Warn( p_intf, "out of memory" );
+            free( p_item->psz_name );
+            free( p_item->psz_author );
+            free( p_item );
+            return;
+        }
+        p_item->psz_uri = psz_uri;
+        memcpy( psz_uri, "sdp://", 6 );
+        psz_uri += 6;
+        memcpy( psz_uri, p_sd->psz_sdp, strlen( p_sd->psz_sdp ) + 1 );
+        /* Enqueueing p_item in the playlist */
+        p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+        playlist_AddItem ( p_playlist, p_item, PLAYLIST_CHECK_INSERT, PLAYLIST_END );
+        vlc_object_release( p_playlist );
+        return;
+    }        
+        
     cfield_parse( p_sd->psz_connection, &psz_uri_default );
 
     for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
@@ -517,6 +674,32 @@ static void sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
             {
                 psz_http_path = strdup(  p_sd->pp_attributes[i]->psz_value );
             }
+            if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup"))
+            {
+                int i_id;
+                p_playlist =
+                (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                                        FIND_ANYWHERE );
+                if( p_playlist == NULL )
+                {
+                    return;
+                }
+
+                i_id = playlist_GroupToId( p_playlist,
+                                           p_sd->pp_attributes[i]->psz_value);
+                if( i_id != 0 )
+                {
+                    p_item->i_group = i_id;
+                }
+                else
+                {
+                    playlist_group_t *p_group =
+                            playlist_CreateGroup( p_playlist,
+                                       p_sd->pp_attributes[i]->psz_value);
+                    p_item->i_group = p_group->i_id;
+                }
+                vlc_object_release( p_playlist );
+            }
         }
 
 
@@ -580,6 +763,8 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
     sd = malloc( sizeof( sess_descr_t ) );
     sd->psz_sessionname = NULL;
     sd->psz_connection  = NULL;
+    sd->psz_sdp         = strdup( p_packet );
+    
     sd->i_media         = 0;
     sd->pp_media        = NULL;
     sd->i_attributes    = 0;
@@ -599,6 +784,10 @@ static sess_descr_t *  parse_sdp( intf_thread_t * p_intf, char *p_packet )
         {
             psz_end = p_packet + strlen( p_packet );
         }
+        if( psz_end > p_packet && *(psz_end - 1 ) == '\r' )
+        {
+            psz_end--;
+        }
 
         if( psz_end <= p_packet )
         {
@@ -687,16 +876,19 @@ static void free_sd( sess_descr_t * p_sd )
 
     FREE( p_sd->psz_sessionname );
     FREE( p_sd->psz_connection );
+    FREE( p_sd->psz_sdp );
 
     for( i = 0; i < p_sd->i_media ; i++ )
     {
         FREE( p_sd->pp_media[i]->psz_medianame );
         FREE( p_sd->pp_media[i]->psz_mediaconnection );
+        FREE( p_sd->pp_media[i] );
     }
     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[i] );
     }
     FREE( p_sd->pp_attributes );
     FREE( p_sd->pp_media );
@@ -778,4 +970,3 @@ static ssize_t NetRead( intf_thread_t *p_intf,
     return 0;
 #endif
 }
-