* 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
#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"
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 );
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;
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 );
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)" );
{
/* 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)" );
fdv6 = socket_desc.i_handle;
}
-
+
/* read SAP packets */
while( !p_intf->b_die )
{
}
/* 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" );
+ }
+ }
}
/********************************************************************
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;
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;
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 );
vlc_object_release( p_playlist );
}
-
+ if( psz_http_path )
+ free(psz_http_path);
}
-
return 1;
}
//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);
}
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] != '='))
{
}
sd->pp_media = NULL;
+ sd->pp_attributes = NULL;
sd->psz_origin = NULL;
sd->psz_sessionname = NULL;
sd->psz_information = NULL;
sd->psz_attribute = NULL;
sd->psz_connection = NULL;
- sd->i_media = 0;
+
+ sd->i_media = 0;
+ sd->i_attributes = 0;
while( *p_packet != '\0' )
{
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' ):
{
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;
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 );
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
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 );
}
else if( i_ret > 0 )
{
- /* Get the data */
+ /* Get the data */
if(i_handle >0)
{
if(FD_ISSET( i_handle, &fds ))
i_recv = recv( i_handle_v6, p_buffer, i_len, 0 );
}
}
-
+
if( i_recv < 0 )
{
msg_Err( p_intf, "recv failed (%s)", strerror(errno) );