* sap.c : SAP interface module
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: sap.c,v 1.5 2002/12/10 00:02:29 gitan Exp $
+ * $Id: sap.c,v 1.35 2003/11/12 20:01:01 gbazin Exp $
*
* Authors: Arnaud Schauly <gitan@via.ecp.fr>
+ * Clément Stenac <zorglub@via.ecp.fr>
+ * Damien Lucas <nitrox@videolan.org>
+ * Laurent Aimar <fenrir@via.ecp.fr>
*
* 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
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
-#include <string.h>
-
-#include <errno.h> /* ENOMEM */
-#include <stdio.h>
-#include <ctype.h>
-#include <signal.h>
#include <vlc/vlc.h>
#include <vlc/intf.h>
-#include <vlc/vout.h>
+
+#include <errno.h> /* ENOMEM */
+#include <ctype.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
-#include <sys/types.h>
-
#ifdef WIN32
# include <winsock2.h>
# endif
#endif
+#ifdef UNDER_CE
+# define close(a) CloseHandle(a)
+#elif defined( WIN32 )
+# define close(a) closesocket(a)
+#endif
+
#include "network.h"
#define MAX_LINE_LENGTH 256
#define HELLO_GROUP "224.2.127.254"
#define ADD_SESSION 1
+#define IPV6_ADDR_1 "FF0" /* Scope is inserted between them */
+#define IPV6_ADDR_2 "::2:7FFE"
+
+
/*****************************************************************************
- * Local prototypes
+ * 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)")
+
+static int Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
-typedef struct media_descr_t media_descr_t;
-typedef struct sess_descr_t sess_descr_t;
+vlc_module_begin();
+ add_category_hint( N_("SAP"), NULL, VLC_TRUE );
+ add_string( "sap-addr", NULL, NULL,
+ SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
+
+ add_bool( "sap-ipv4", 1 , NULL,
+ SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE);
-static int Activate ( vlc_object_t * );
-static void Run ( intf_thread_t *p_intf );
-static int Kill ( intf_thread_t * );
+ add_bool( "sap-ipv6", 0 , NULL,
+ SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE);
-static ssize_t NetRead ( intf_thread_t*, int , byte_t *, size_t );
+ add_string( "sap-ipv6-scope", "8" , NULL,
+ SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
-/* playlist related functions */
-static int sess_toitem( intf_thread_t *, sess_descr_t * );
+ set_description( _("SAP interface") );
+ set_capability( "interface", 0 );
+ set_callbacks( Open, Close );
+vlc_module_end();
-/* sap/sdp related functions */
-static int parse_sap ( char ** );
-static int packet_handle ( intf_thread_t *, char ** );
-static sess_descr_t * parse_sdp( char *,intf_thread_t * ) ;
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
-/* specific sdp fields parsing */
+static void Run ( intf_thread_t *p_intf );
+static ssize_t NetRead( intf_thread_t *, int fd[2], uint8_t *, int );
-static void cfield_parse( char *, char ** );
-static void mfield_parse( char *psz_mfield, char **ppsz_proto,
- char **ppsz_port );
+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 void sess_toitem( intf_thread_t *, sess_descr_t * );
+static sess_descr_t * parse_sdp( intf_thread_t *, char * ) ;
static void free_sd( sess_descr_t * );
+
+/* Detect multicast addresses */
static int ismult( char * );
/* The struct that contains sdp informations */
-struct sess_descr_t {
- char *psz_version;
- char *psz_origin;
+struct sess_descr_t
+{
+ int i_version;
char *psz_sessionname;
- char *psz_information;
- char *psz_uri;
- char *psz_emails;
- char *psz_phone;
- char *psz_time;
- char *psz_repeat;
- char *psz_attribute;
char *psz_connection;
- int i_media;
- media_descr_t ** pp_media;
+
+ int i_media;
+ media_descr_t **pp_media;
+ int i_attributes;
+ 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;
};
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-vlc_module_begin();
- add_category_hint( N_("SAP"), NULL );
- add_string( "sap-addr", NULL, NULL,
- "SAP multicast address", "SAP multicast address" );
- set_description( _("SAP interface module") );
- set_capability( "interface", 0 );
- set_callbacks( Activate, NULL);
-vlc_module_end();
-
-/*****************************************************************************
- * Activate: initialize and create stuff
- *****************************************************************************/
-static int Activate( vlc_object_t *p_this )
+struct attr_descr_t
{
- intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ char *psz_field;
+ char *psz_value;
+};
- p_intf->pf_run = Run;
+struct intf_sys_t
+{
+ /* IPV4 and IPV6 */
+ int fd[2];
- return VLC_SUCCESS;
-}
+ /* playlist group */
+ int i_group;
+};
/*****************************************************************************
- * Run: sap thread
- *****************************************************************************
- * Listens to SAP packets, and sends them to packet_handle
+ * Open: initialize and create stuff
*****************************************************************************/
-
-static void Run( intf_thread_t *p_intf )
+static int Open( vlc_object_t *p_this )
{
- char *psz_addr;
- char *psz_network = NULL;
- struct sockaddr_in addr;
- int fd,addrlen;
- char *psz_buf;
-
- module_t *p_network;
- network_socket_t socket_desc;
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ intf_sys_t *p_sys = malloc( sizeof( intf_sys_t ) );
- psz_buf = NULL;
+ playlist_t *p_playlist;
- if( !(psz_addr = config_GetPsz( p_intf, "sap-addr" ) ) )
+ p_sys->fd[0] = -1;
+ p_sys->fd[1] = -1;
+ if( config_GetInt( p_intf, "sap-ipv4" ) )
{
- 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;
- p_intf->p_private = (void*) &socket_desc;
-
- psz_network = "ipv4"; // FIXME
-
- /* Create, Bind the socket, ... with the appropriate module */
+ char *psz_address = config_GetPsz( p_intf, "sap-addr" );
+ network_socket_t sock;
+ module_t *p_network;
+ if( psz_address == NULL || *psz_address == '\0' )
+ {
+ psz_address = strdup( HELLO_GROUP );
+ }
- if( !( p_network = module_Need( p_intf, "network", psz_network ) ) )
- {
- msg_Err( p_intf, "failed to open a connection (udp)" );
- return;
+ /* Prepare the network_socket_t structure */
+ sock.i_type = NETWORK_UDP;
+ sock.psz_bind_addr = psz_address;
+ sock.i_bind_port = HELLO_PORT;
+ sock.psz_server_addr = "";
+ sock.i_server_port = 0;
+ sock.i_ttl = 0;
+ p_intf->p_private = (void*) &sock;
+
+ p_network = module_Need( p_intf, "network", "ipv4" );
+ if( p_network )
+ {
+ p_sys->fd[0] = sock.i_handle;
+ module_Unneed( p_intf, p_network );
+ }
+ else
+ {
+ msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
+ }
+ free( psz_address );
}
- module_Unneed( p_intf, p_network );
-
- fd = socket_desc.i_handle;
-
-
- /* read SAP packets */
-
- psz_buf = malloc( 2000 );
- while( !p_intf->b_die )
+ if( config_GetInt( p_intf, "sap-ipv6" ) )
{
- int i_read;
- addrlen=sizeof(addr);
-
-
- memset(psz_buf, 0, 2000);
+ char psz_address[100];
+ char *psz_scope = config_GetPsz( p_intf, "sap-ipv6-scope" );
+ network_socket_t sock;
+ module_t *p_network;
- i_read = NetRead( p_intf, fd, psz_buf, 2000 );
-
- if( i_read < 0 )
+ if( psz_scope == NULL || *psz_scope == '\0' )
{
- msg_Err( p_intf, "Cannot read in the socket" );
+ psz_scope = strdup( "8" );
}
- if( i_read == 0 )
+ snprintf( psz_address, 100, "[%s%c%s]",IPV6_ADDR_1, psz_scope[0], IPV6_ADDR_2 );
+ free( psz_scope );
+
+ sock.i_type = NETWORK_UDP;
+ sock.psz_bind_addr = psz_address;
+ sock.i_bind_port = HELLO_PORT;
+ sock.psz_server_addr = "";
+ sock.i_server_port = 0;
+ sock.i_ttl = 0;
+ p_intf->p_private = (void*) &sock;
+
+ p_network = module_Need( p_intf, "network", "ipv6" );
+ if( p_network )
{
- continue;
+ p_sys->fd[1] = sock.i_handle;
+ module_Unneed( p_intf, p_network );
+ }
+ else
+ {
+ msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
}
-
-
- packet_handle( p_intf, &psz_buf );
-
}
- free( psz_buf );
+ if( p_sys->fd[0] <= 0 && p_sys->fd[1] <= 0 )
+ {
+ msg_Warn( p_intf, "IPV4 and IPV6 failed" );
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
- /* Closing socket */
+ /* Create our playlist group */
+ p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+ if( p_playlist )
+ {
+ playlist_group_t *p_group = playlist_CreateGroup( p_playlist , "SAP" );
+ p_sys->i_group = p_group->i_id;
+ vlc_object_release( p_playlist );
+ }
-#ifdef UNDER_CE
- CloseHandle( socket_desc.i_handle );
-#elif defined( WIN32 )
- closesocket( socket_desc.i_handle );
-#else
- close( socket_desc.i_handle );
-#endif
+ p_intf->pf_run = Run;
+ p_intf->p_sys = p_sys;
+ return VLC_SUCCESS;
}
-/********************************************************************
- * Kill
- *******************************************************************
- * Kills the SAP interface.
- ********************************************************************/
-static int Kill( intf_thread_t *p_intf )
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
{
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ intf_sys_t *p_sys = p_intf->p_sys;
- p_intf->b_die = VLC_TRUE;
+ if( p_sys->fd[0] > 0 )
+ {
+ close( p_sys->fd[0] );
+ }
+ if( p_sys->fd[1] > 0 )
+ {
+ close( p_sys->fd[1] );
+ }
- return VLC_SUCCESS;
+ free( p_sys );
}
-/*******************************************************************
- * sess_toitem : changes a sess_descr_t into a hurd of
- * playlist_item_t, which are enqueued.
- *******************************************************************
- * Note : does not support sessions that take place on consecutive
- * port or adresses yet.
- *******************************************************************/
+/*****************************************************************************
+ * Run: sap thread
+ *****************************************************************************
+ * Listens to SAP packets, and sends them to packet_handle
+ *****************************************************************************/
+#define MAX_SAP_BUFFER 2000
-static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
+static void Run( intf_thread_t *p_intf )
{
- playlist_item_t * p_item;
- char *psz_uri, *psz_proto;
- char *psz_port;
- char *psz_uri_default;
- int i_multicast;
- int i_count;
- playlist_t *p_playlist;
-
- psz_uri_default = NULL;
- cfield_parse( p_sd->psz_connection, &psz_uri_default );
+ intf_sys_t *p_sys = p_intf->p_sys;
+ uint8_t buffer[MAX_SAP_BUFFER + 1];
- for( i_count=0 ; i_count <= p_sd->i_media ; i_count ++ )
+ /* 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;
- p_item = malloc( sizeof( playlist_item_t ) );
- p_item->psz_name = strdup( p_sd->psz_sessionname );
- p_item->i_type = 0;
- p_item->i_status = 0;
- p_item->b_autodeletion = VLC_FALSE;
- p_item->psz_uri = NULL;
-
- psz_uri = NULL;
-
- /* Build what we have to put in p_item->psz_uri, with the m and
- * c fields */
-
- if( !p_sd->pp_media[i_count] )
- {
- return 0;
- }
-
- mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
- & psz_proto, & psz_port );
-
- if( !psz_proto || !psz_port )
+ /* Minimum length is > 6 */
+ if( i_read <= 6 )
{
- return 0;
- }
-
- if( p_sd->pp_media[i_count]->psz_mediaconnection )
- {
- cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
- & psz_uri );
- }
- else
- {
- psz_uri = NULL;
- }
-
- if( psz_uri == NULL )
- {
- if( psz_uri_default )
+ if( i_read < 0 )
{
- psz_uri = psz_uri_default;
- }
- else
- {
- return 0;
+ msg_Warn( p_intf, "Cannot read in the socket" );
}
+ continue;
}
+ buffer[i_read] = '\0';
- /* Filling p_item->psz_uri */
- i_multicast = ismult( psz_uri );
+ /* Parse the SAP header */
+ p_sdp = &buffer[4];
+ p_sdp += (buffer[0]&0x10) ? 16 : 4;
+ p_sdp += buffer[1];
- p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
- strlen( psz_port ) + 5 +i_multicast );
- if( p_item->psz_uri == NULL )
+ while( p_sdp < &buffer[i_read-1] && *p_sdp != '\0' && p_sdp[0] != 'v' && p_sdp[1] != '=' )
{
- msg_Err( p_intf, "Not enough memory");
- return 0;
+ p_sdp++;
}
-
- if( i_multicast == 1)
+ if( *p_sdp == '\0' )
{
- sprintf( p_item->psz_uri, "%s://@%s:%s", psz_proto,
- psz_uri, psz_port );
+ p_sdp++;
}
- else
+ if( p_sdp < &buffer[i_read] )
{
- sprintf( p_item->psz_uri, "%s://%s:%s", psz_proto,
- psz_uri, psz_port );
- }
-
- /* Enqueueing p_item in the playlist */
-
- if( p_item )
- {
- 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 );
+ sess_descr_t *p_sd = parse_sdp( p_intf, p_sdp );
+ if( p_sd )
+ {
+ sess_toitem ( p_intf, p_sd );
+ free_sd ( p_sd );
+ }
}
-
-
}
-
-
- return 1;
-
}
/**********************************************************************
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++;
}
*psz_pos = '\0';
psz_pos++;
*ppsz_proto = psz_pos;
- while( *psz_pos!='\0' && *psz_pos !=' ' &&
+ while( *psz_pos!='\0' && *psz_pos !=' ' &&
*psz_pos!='/' )
{
*psz_pos = tolower( *psz_pos );
return;
}
-/***********************************************************************
- * parse_sap : Takes care of the SAP headers
- ***********************************************************************
- * checks if the packet has the true headers ;
- ***********************************************************************/
-static int parse_sap( char ** ppsz_sa_packet ) { /* Dummy Parser : does nothing !*/
- if( *ppsz_sa_packet ) return ADD_SESSION; //Add this packet
- return 0; /* FIXME */
-}
+/*******************************************************************
+ * sess_toitem : changes a sess_descr_t into a hurd of
+ * playlist_item_t, which are enqueued.
+ *******************************************************************
+ * Note : does not support sessions that take place on consecutive
+ * port or adresses yet.
+ *******************************************************************/
+
+static void sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
+{
+ playlist_item_t * p_item;
+ char *psz_uri, *psz_proto;
+ char *psz_port;
+ char *psz_uri_default;
+ int i_count , i;
+ vlc_bool_t b_http = VLC_FALSE;
+ char *psz_http_path = NULL;
+ playlist_t *p_playlist = NULL;
+
+ psz_uri_default = NULL;
+ cfield_parse( p_sd->psz_connection, &psz_uri_default );
+
+ for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
+ {
+ p_item = malloc( sizeof( playlist_item_t ) );
+ 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 = NULL;
-/*************************************************************************
- * packet_handle : handle the received packet and enques the
- * the understated session
- *************************************************************************/
+ /* Build what we have to put in p_item->psz_uri, with the m and
+ * c fields */
-static int packet_handle( intf_thread_t * p_intf, char ** ppsz_packet ) {
- int j=0;
- sess_descr_t * p_sd;
+ if( !p_sd->pp_media[i_count] )
+ {
+ return;
+ }
- j=parse_sap( ppsz_packet );
+ mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
+ & psz_proto, & psz_port );
- if(j != 0) {
+ if( !psz_proto || !psz_port )
+ {
+ return;
+ }
- p_sd = parse_sdp( *ppsz_packet, p_intf );
+ if( p_sd->pp_media[i_count]->psz_mediaconnection )
+ {
+ cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
+ & psz_uri );
+ }
+ else
+ {
+ psz_uri = psz_uri_default;
+ }
+ if( psz_uri == NULL )
+ {
+ return;
+ }
- sess_toitem ( p_intf, p_sd );
+ 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 );
+ }
+ 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;
+ }
- free_sd ( p_sd );
- return 1;
- }
- return 0; // Invalid Packet
-}
+ 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 );
+ }
+ }
+
+
+ /* Filling p_item->psz_uri */
+ if( b_http == VLC_FALSE )
+ {
+ p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
+ strlen( psz_port ) + 7 );
+ if( ismult( psz_uri ) )
+ {
+ 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
+ {
+ if( psz_http_path == NULL )
+ {
+ psz_http_path = strdup( "/" );
+ }
+ p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
+ strlen( psz_port ) + strlen(psz_http_path) + 5 );
+ sprintf( p_item->psz_uri, "%s://%s:%s%s", psz_proto,
+ psz_uri, psz_port,psz_http_path );
+ if( psz_http_path )
+ {
+ free( psz_http_path );
+ }
+ }
+ /* 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 );
+ }
+}
/***********************************************************************
* parse_sdp : SDP parsing
* Make a sess_descr_t with a psz
***********************************************************************/
-static sess_descr_t * parse_sdp( char * psz_pct, intf_thread_t * p_intf )
+static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
{
- int j,k;
- char ** ppsz_fill=NULL;
sess_descr_t * sd;
- sd = malloc( sizeof(sess_descr_t) );
-
-
- if( sd == NULL )
+ if( p_packet[0] != 'v' || p_packet[1] != '=' )
{
- msg_Err( p_intf, "out of memory" );
+ msg_Warn(p_intf, "bad SDP packet");
+ return NULL;
}
- else
+
+ sd = malloc( sizeof( sess_descr_t ) );
+ sd->psz_sessionname = NULL;
+ sd->psz_connection = NULL;
+ sd->i_media = 0;
+ sd->pp_media = NULL;
+ sd->i_attributes = 0;
+ sd->pp_attributes = NULL;
+
+ while( *p_packet != '\0' )
{
- sd->pp_media = NULL;
- sd->psz_origin = NULL;
- sd->psz_sessionname = NULL;
- sd->psz_information = NULL;
- sd->psz_uri = NULL;
- sd->psz_emails = NULL;
- sd->psz_phone = NULL;
- sd->psz_time = NULL;
- sd->psz_repeat = NULL;
- sd->psz_attribute = NULL;
- sd->psz_connection = NULL;
-
- sd->i_media=-1;
- j=0;
- while( psz_pct[j]!=EOF && psz_pct[j] != '\0' )
- {
- j++;
- if (psz_pct[j] == '=')
- {
- switch(psz_pct[(j-1)]) {
- case ('v') : {
- ppsz_fill = & sd->psz_version;
- break;
- }
- case ('o') : {
- ppsz_fill = & sd->psz_origin;
- break;
- }
- case ('s') : {
- ppsz_fill = & sd->psz_sessionname;
- break;
- }
- case ('i') : {
- ppsz_fill = & sd->psz_information;
- break;
- }
- case ('u') : {
- ppsz_fill = & sd->psz_uri;
- break;
- }
- case ('e') : {
- ppsz_fill = & sd->psz_emails;
- break;
- }
- case ('p') : {
- ppsz_fill = & sd->psz_phone;
- break;
- }
- case ('t') : {
- ppsz_fill = & sd->psz_time;
- break;
- }
- case ('r') : {
- ppsz_fill = & sd->psz_repeat;
- break;
- }
- case ('a') : {
- ppsz_fill = & sd->psz_attribute;
- break;
- }
- case ('m') : {
- sd->i_media++;
- if( sd->pp_media ) {
- sd->pp_media = realloc( sd->pp_media,
- ( sizeof( void * ) * (sd->i_media + 1)) );
- }
- else
- {
- sd->pp_media = malloc( sizeof ( void * ) );
- }
- 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;
-
- ppsz_fill = & sd->pp_media[sd->i_media]->psz_medianame;
- break;
- }
- case ('c') : {
- if( sd->i_media == -1 )
- {
- ppsz_fill = & sd->psz_connection;
- }
- else
- {
- ppsz_fill = & sd->pp_media[sd->i_media]->
- psz_mediaconnection;
- }
- break;
- }
+ char *psz_end;
+
+ /* Search begin of field */
+ while( *p_packet == '\n' || *p_packet == ' ' || *p_packet == '\t' )
+ {
+ p_packet++;
+ }
+ /* search end of line */
+ if( ( psz_end = strchr( p_packet, '\n' ) ) == NULL )
+ {
+ psz_end = p_packet + strlen( p_packet );
+ }
+ if( psz_end > p_packet && *(psz_end - 1 ) == '\r' )
+ {
+ psz_end--;
+ }
+
+ if( psz_end <= p_packet )
+ {
+ break;
+ }
+ *psz_end++ = '\0';
+
+ if( p_packet[1] != '=' )
+ {
+ msg_Warn( p_intf, "packet invalid" );
+ free_sd( sd );
+ return NULL;
+ }
+
+ switch( p_packet[0] )
+ {
+ case( 'v' ):
+ sd->i_version = atoi( &p_packet[2] );
+ break;
+ case( 's' ):
+ sd->psz_sessionname = strdup( &p_packet[2] );
+ break;
+ case ( 'o' ):
+ case( 'i' ):
+ case( 'u' ):
+ case( 'e' ):
+ case( 'p' ):
+ case( 't' ):
+ case( 'r' ):
+ break;
+ case( 'a' ):
+ {
+ char *psz_eof = strchr( &p_packet[2], ':' );
+
+ if( psz_eof && psz_eof[1] != '\0' )
+ {
+ attr_descr_t *attr = malloc( sizeof( attr_descr_t ) );
- default : {
- ppsz_fill = NULL;
+ *psz_eof++ = '\0';
+
+ attr->psz_field = strdup( &p_packet[2] );
+ attr->psz_value = strdup( psz_eof );
+
+ TAB_APPEND( sd->i_attributes, sd->pp_attributes, attr );
}
+ break;
+ }
+ case( 'm' ):
+ {
+ media_descr_t *media = malloc( sizeof( media_descr_t ) );
- }
- k=0;j++;
+ media->psz_medianame = strdup( &p_packet[2] );
+ media->psz_mediaconnection = NULL;
- while (psz_pct[j] != '\n'&& psz_pct[j] != EOF) {
- k++; j++;
- }
- j--;
+ TAB_APPEND( sd->i_media, sd->pp_media, media );
+ break;
+ }
- if( ppsz_fill != NULL )
- {
- *ppsz_fill= malloc( sizeof(char) * (k+1) );
- memcpy(*ppsz_fill, &(psz_pct[j-k+1]), k );
- (*ppsz_fill)[k]='\0';
- }
- ppsz_fill = NULL;
- } // if
- } //for
- } //if
+ case( 'c' ):
+ if( sd->i_media <= 0 )
+ {
+ sd->psz_connection = strdup( &p_packet[2] );
+ }
+ else
+ {
+ sd->pp_media[sd->i_media-1]->psz_mediaconnection = strdup( &p_packet[2] );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ p_packet = psz_end;
+ }
return sd;
}
static void free_sd( sess_descr_t * p_sd )
{
int i;
- if( p_sd )
- {
- FREE( p_sd->psz_origin );
FREE( p_sd->psz_sessionname );
- FREE( p_sd->psz_information );
- FREE( p_sd->psz_uri );
- FREE( p_sd->psz_emails );
- FREE( p_sd->psz_phone );
- FREE( p_sd->psz_time );
- FREE( p_sd->psz_repeat );
- FREE( p_sd->psz_attribute );
FREE( p_sd->psz_connection );
- if( p_sd->i_media >= 0 && p_sd->pp_media )
+ for( i = 0; i < p_sd->i_media ; i++ )
{
- 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 );
+ FREE( p_sd->pp_media[i]->psz_medianame );
+ FREE( p_sd->pp_media[i]->psz_mediaconnection );
}
- free( p_sd );
- }
- else
+ 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 );
}
- return;
+ FREE( p_sd->pp_attributes );
+ FREE( p_sd->pp_media );
+
+ free( p_sd );
}
/***********************************************************************
- * ismult
+ * ismult: returns true if we have a multicast address
***********************************************************************/
static int ismult( char *psz_uri )
{
- char *psz_c;
- int i;
+ char *psz_end;
+ int i_value;
- psz_c = malloc( 3 );
+ i_value = strtol( psz_uri, &psz_end, 0 );
- memcpy( psz_c, psz_uri, 3 );
- if( psz_c[2] == '.' || psz_c[1] == '.' )
+ /* IPv6 */
+ if( psz_uri[0] == '[')
{
- free( psz_c );
- return 0;
+ if( strncasecmp( &psz_uri[1], "FF0" , 3) ||
+ strncasecmp( &psz_uri[2], "FF0" , 3))
+ return( VLC_TRUE );
+ else
+ return( VLC_FALSE );
}
- i = atoi( psz_c );
- if( i < 224 )
- {
- free( psz_c );
- return 0;
- }
+ if( *psz_end != '.' ) { return( VLC_FALSE ); }
- free( psz_c );
- return 1;
+ 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, byte_t *p_buffer, size_t i_len)
+ int fd[2], uint8_t *p_buffer, int i_len )
{
#ifdef UNDER_CE
return -1;
-
#else
struct timeval timeout;
fd_set fds;
int i_ret;
+ int i_handle_max = __MAX( fd[0], fd[1] );
/* Initialize file descriptor set */
FD_ZERO( &fds );
- FD_SET( i_handle, &fds );
+ if( fd[0] > 0 ) FD_SET( fd[0], &fds );
+ if( fd[1] > 0 ) FD_SET( fd[1], &fds );
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
/* Find if some data is available */
- i_ret = select( i_handle + 1, &fds,
- NULL, NULL, &timeout );
+ i_ret = select( i_handle_max + 1, &fds, NULL, NULL, &timeout );
if( i_ret == -1 && errno != EINTR )
{
}
else if( i_ret > 0 )
{
- ssize_t i_recv = recv( i_handle, p_buffer, i_len, 0 );
-
- if( i_recv < 0 )
+ if( fd[0] > 0 && FD_ISSET( fd[0], &fds ) )
{
- msg_Err( p_intf, "recv failed (%s)", strerror(errno) );
+ return recv( fd[0], p_buffer, i_len, 0 );
+ }
+ else if( fd[1] > 0 && FD_ISSET( fd[1], &fds ) )
+ {
+ return recv( fd[1], p_buffer, i_len, 0 );
}
-
- return i_recv;
}
-
return 0;
-
#endif
}
-