Commit 3f41f383 authored by Laurent Aimar's avatar Laurent Aimar

* sap: big clean up + some buffer overflow fixes (still need some work).

parent 313cc2da
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
* sap.c : SAP interface module * sap.c : SAP interface module
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: sap.c,v 1.29 2003/11/03 22:36:45 sam Exp $ * $Id: sap.c,v 1.30 2003/11/05 23:28:36 fenrir Exp $
* *
* Authors: Arnaud Schauly <gitan@via.ecp.fr> * Authors: Arnaud Schauly <gitan@via.ecp.fr>
* Clment Stenac <zorglub@via.ecp.fr> * Clment Stenac <zorglub@via.ecp.fr>
* Damien Lucas <nitrox@videolan.org> * Damien Lucas <nitrox@videolan.org>
* Laurent Aimar <fenrir@via.ecp.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -27,26 +28,19 @@ ...@@ -27,26 +28,19 @@
* Preamble * Preamble
*****************************************************************************/ *****************************************************************************/
#include <stdlib.h> /* malloc(), free() */ #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/vlc.h>
#include <vlc/intf.h> #include <vlc/intf.h>
#include <vlc/vout.h>
#include <errno.h> /* ENOMEM */
#include <ctype.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>
#endif #endif
#include <sys/types.h>
#ifdef WIN32 #ifdef WIN32
# include <winsock2.h> # include <winsock2.h>
...@@ -82,82 +76,10 @@ ...@@ -82,82 +76,10 @@
#define IPV6_ADDR_1 "FF0" /* Scope is inserted between them */ #define IPV6_ADDR_1 "FF0" /* Scope is inserted between them */
#define IPV6_ADDR_2 "::2:7FFE" #define IPV6_ADDR_2 "::2:7FFE"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
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 );
static int Kill ( intf_thread_t * );
static ssize_t NetRead ( intf_thread_t*, int, int , byte_t *, size_t );
/* playlist related functions */
static int sess_toitem( intf_thread_t *, sess_descr_t * );
/* sap/sdp related functions */
static int parse_sap ( char * );
static int packet_handle ( intf_thread_t *, char *, int );
static sess_descr_t * parse_sdp( intf_thread_t *, char * ) ;
/* specific sdp fields parsing */
static void cfield_parse( char *, char ** );
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
{
char *psz_version;
char *psz_origin;
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;
int i_attributes;
media_descr_t ** pp_media;
attr_descr_t ** pp_attributes;
};
/* All this informations are not useful yet. */
struct media_descr_t
{
char *psz_medianame;
char *psz_mediaconnection;
};
struct attr_descr_t
{
char *psz_field;
char *psz_value;
};
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
#define SAP_ADDR_TEXT N_("SAP multicast address") #define SAP_ADDR_TEXT N_("SAP multicast address")
#define SAP_ADDR_LONGTEXT N_("SAP multicast address") #define SAP_ADDR_LONGTEXT N_("SAP multicast address")
#define SAP_IPV4_TEXT N_("IPv4-SAP listening") #define SAP_IPV4_TEXT N_("IPv4-SAP listening")
...@@ -167,6 +89,9 @@ struct attr_descr_t ...@@ -167,6 +89,9 @@ struct attr_descr_t
#define SAP_SCOPE_TEXT N_("IPv6 SAP scope") #define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
#define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)") #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 * );
vlc_module_begin(); vlc_module_begin();
add_category_hint( N_("SAP"), NULL, VLC_TRUE ); add_category_hint( N_("SAP"), NULL, VLC_TRUE );
add_string( "sap-addr", NULL, NULL, add_string( "sap-addr", NULL, NULL,
...@@ -183,347 +108,236 @@ vlc_module_begin(); ...@@ -183,347 +108,236 @@ vlc_module_begin();
set_description( _("SAP interface") ); set_description( _("SAP interface") );
set_capability( "interface", 0 ); set_capability( "interface", 0 );
set_callbacks( Activate, NULL); set_callbacks( Open, Close );
vlc_module_end(); vlc_module_end();
/***************************************************************************** /*****************************************************************************
* Activate: initialize and create stuff * Local prototypes
*****************************************************************************/
static int Activate( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t*)p_this;
p_intf->pf_run = Run;
return VLC_SUCCESS;
}
/*****************************************************************************
* Run: sap thread
*****************************************************************************
* Listens to SAP packets, and sends them to packet_handle
*****************************************************************************/ *****************************************************************************/
#define MAX_SAP_BUFFER 2000
static void Run( intf_thread_t *p_intf ) static void Run ( intf_thread_t *p_intf );
{ static int NetRead( intf_thread_t *, int fd[2], uint8_t *, int );
char *psz_addr;
char *psz_addrv6;
char *psz_network = NULL;
int fd = - 1;
int fdv6 = -1;
int sap_ipv4 = config_GetInt( p_intf, "sap-ipv4" ); typedef struct media_descr_t media_descr_t;
int sap_ipv6 = config_GetInt( p_intf, "sap-ipv6" ); typedef struct sess_descr_t sess_descr_t;
char *sap_ipv6_scope = config_GetPsz( p_intf, "sap-ipv6-scope" ); typedef struct attr_descr_t attr_descr_t;
char buffer[MAX_SAP_BUFFER + 1]; static void sess_toitem( intf_thread_t *, sess_descr_t * );
module_t *p_network; static sess_descr_t * parse_sdp( intf_thread_t *, char * ) ;
network_socket_t socket_desc; static void free_sd( sess_descr_t * );
playlist_t *p_playlist;
playlist_group_t *p_group;
if( sap_ipv4 == -1 || sap_ipv6 == -1 || sap_ipv6_scope == NULL ) /* Detect multicast addresses */
{ static int ismult( char * );
msg_Warn( p_intf, "unable to parse module configuration" );
return;
}
/* The struct that contains sdp informations */
struct sess_descr_t
{
int i_version;
char *psz_sessionname;
char *psz_connection;
p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); int i_media;
if( !p_intf->p_sys ) media_descr_t **pp_media;
{ int i_attributes;
msg_Err( p_intf, "out of memory"); attr_descr_t **pp_attributes;
p_intf->b_die = VLC_TRUE; };
return;
}
/* Create our playlist group */ /* All this informations are not useful yet. */
p_playlist = struct media_descr_t
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, {
FIND_ANYWHERE ); char *psz_medianame;
p_group = playlist_CreateGroup( p_playlist , "SAP" ); char *psz_mediaconnection;
p_intf->p_sys->i_group = p_group->i_id; };
vlc_object_release( p_playlist ); struct attr_descr_t
{
char *psz_field;
char *psz_value;
};
/* Prepare IPv4 Networking */ struct intf_sys_t
if ( sap_ipv4 == 1) {
{ /* IPV4 and IPV6 */
if( !(psz_addr = config_GetPsz( p_intf, "sap-addr" ) ) ) int fd[2];
{
psz_addr = strdup( HELLO_GROUP );
}
/* Prepare the network_socket_t structure */ /* playlist group */
socket_desc.i_type = NETWORK_UDP; int i_group;
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"; /*****************************************************************************
* Open: initialize and create stuff
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t*)p_this;
intf_sys_t *p_sys = malloc( sizeof( intf_sys_t ) );
/* Create, Bind the socket, ... with the appropriate module */ playlist_t *p_playlist;
if( !( p_network = module_Need( p_intf, "network", psz_network ) ) ) p_sys->fd[0] = -1;
p_sys->fd[1] = -1;
if( config_GetInt( p_intf, "sap-ipv4" ) )
{
char *psz_address = config_GetPsz( p_intf, "sap-addr" );
network_socket_t sock;
module_t *p_network;
if( psz_address == NULL || *psz_address == '\0' )
{ {
msg_Warn( p_intf, "failed to open a UDP connection" ); psz_address = strdup( HELLO_GROUP );
p_intf->b_die = VLC_TRUE;
return;
} }
module_Unneed( p_intf, p_network );
fd = socket_desc.i_handle;
}
/* Prepare IPv6 Networking */
if ( sap_ipv6 > 0)
{
/* Prepare the network_socket_t structure */ /* 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;
psz_addrv6=(char *)malloc(sizeof(char)*38); p_network = module_Need( p_intf, "network", "ipv4" );
if( p_network )
if( !psz_addrv6)
{ {
msg_Warn( p_intf, "out of memory" ); p_sys->fd[0] = sock.i_handle;
module_Unneed( p_intf, p_network );
} }
/* Max size of an IPv6 address */ else
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";
/* 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 UDP connection" ); msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
p_intf->b_die = VLC_TRUE;
return;
} }
module_Unneed( p_intf, p_network ); free( psz_address );
fdv6 = socket_desc.i_handle;
} }
if( config_GetInt( p_intf, "sap-ipv6" ) )
/* read SAP packets */
while( !p_intf->b_die )
{ {
int i_read; char psz_address[100];
char *psz_scope = config_GetPsz( p_intf, "sap-ipv6-scope" );
network_socket_t sock;
module_t *p_network;
//memset( buffer, 0, MAX_SAP_BUFFER + 1); if( psz_scope == NULL || *psz_scope == '\0' )
{
psz_scope = strdup( "8" );
}
snprintf( psz_address, 100, "[%s%c%s]",IPV6_ADDR_1, psz_scope[0], IPV6_ADDR_2 );
free( psz_scope );
i_read = NetRead( p_intf, fd, fdv6, buffer, MAX_SAP_BUFFER ); 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;
if( i_read < 0 ) p_network = module_Need( p_intf, "network", "ipv6" );
if( p_network )
{ {
msg_Err( p_intf, "cannot read from socket" ); p_sys->fd[1] = sock.i_handle;
module_Unneed( p_intf, p_network );
} }
if( i_read == 0 ) else
{ {
continue; msg_Warn( p_intf, "failed to open %s:%d", psz_address, HELLO_PORT );
} }
buffer[i_read] = '\0';
packet_handle( p_intf, buffer, i_read );
} }
if( p_sys->fd[0] <= 0 && p_sys->fd[1] <= 0 )
/* Closing socket */
if( fd > 0)
{ {
if( close( fd ) ) msg_Warn( p_intf, "IPV4 and IPV6 failed" );
{ free( p_sys );
msg_Warn( p_intf, "uh-oh, unable to close the socket" ); return VLC_EGENERIC;
}
} }
if( fdv6 > 0)
/* Create our playlist group */
p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist )
{ {
if( close( fdv6 ) ) playlist_group_t *p_group = playlist_CreateGroup( p_playlist , "SAP" );
{ p_sys->i_group = p_group->i_id;
msg_Warn( p_intf, "uh-oh, unable to close the socket" ); vlc_object_release( p_playlist );
}
} }
}
/********************************************************************
* Kill
*******************************************************************
* Kills the SAP interface.
********************************************************************/
static int Kill( intf_thread_t *p_intf )
{
p_intf->b_die = VLC_TRUE; p_intf->pf_run = Run;
p_intf->p_sys = p_sys;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/******************************************************************* /*****************************************************************************
* sess_toitem : changes a sess_descr_t into a hurd of * Close:
* playlist_item_t, which are enqueued. *****************************************************************************/
******************************************************************* static void Close( vlc_object_t *p_this )
* Note : does not support sessions that take place on consecutive
* port or adresses yet.
*******************************************************************/
static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
{ {
playlist_item_t * p_item; intf_thread_t *p_intf = (intf_thread_t*)p_this;
char *psz_uri, *psz_proto; intf_sys_t *p_sys = p_intf->p_sys;
char *psz_port;
char *psz_uri_default;
int i_multicast;
int i_count , i;
vlc_bool_t b_http = VLC_FALSE;
char *psz_http_path = NULL;
playlist_t *p_playlist;
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++ ) if( p_sys->fd[0] > 0 )
{ {
p_item = malloc( sizeof( playlist_item_t ) ); close( p_sys->fd[0] );
if( p_item == NULL ) }
{ if( p_sys->fd[1] > 0 )
msg_Err( p_intf, "out of memory for p_item in sesstoitem()" ); {
return VLC_ENOMEM; close( p_sys->fd[1] );
} }
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;
p_item->ppsz_options = NULL;
p_item->i_options = 0;
psz_uri = NULL; free( p_sys );
}
/* Build what we have to put in p_item->psz_uri, with the m and /*****************************************************************************
* c fields */ * Run: sap thread
*****************************************************************************
* Listens to SAP packets, and sends them to packet_handle
*****************************************************************************/
#define MAX_SAP_BUFFER 2000
if( !p_sd->pp_media[i_count] ) static void Run( intf_thread_t *p_intf )
{ {
return VLC_EGENERIC; intf_sys_t *p_sys = p_intf->p_sys;
} uint8_t buffer[MAX_SAP_BUFFER + 1];
mfield_parse( p_sd->pp_media[i_count]->psz_medianame, /* read SAP packets */
& psz_proto, & psz_port ); while( !p_intf->b_die )
{
int i_read = NetRead( p_intf, p_sys->fd, buffer, MAX_SAP_BUFFER );
uint8_t *p_sdp;
if( !psz_proto || !psz_port ) /* Minimum length is > 6 */
if( i_read <= 6 )
{ {
return VLC_EGENERIC; if( i_read < 0 )
{
msg_Warn( p_intf, "Cannot read in the socket" );
}
continue;
} }
if( p_sd->pp_media[i_count]->psz_mediaconnection ) buffer[i_read] = '\0';
{
cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
& psz_uri );
}
else
{
psz_uri = psz_uri_default;
}
if( psz_uri == NULL ) /* Parse the SAP header */
{ p_sdp = &buffer[4];
return VLC_EGENERIC; p_sdp += (buffer[0]&0x10) ? 16 : 4;
} p_sdp += buffer[1];
for( i = 0 ; i< p_sd->i_attributes ; i++ ) while( p_sdp < &buffer[i_read-1] && *p_sdp != '\0' && p_sdp[0] != 'v' && p_sdp[1] != '=' )
{ {
if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "type") && p_sdp++;
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( *p_sdp == '\0' )
/* Filling p_item->psz_uri */
if( b_http == VLC_FALSE )
{ {
i_multicast = ismult( psz_uri ); p_sdp++;
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, "out of memory");
free( p_item );
return VLC_ENOMEM;
}
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 if( p_sdp < &buffer[i_read] )
{ {
if( psz_http_path == NULL ) sess_descr_t *p_sd = parse_sdp( p_intf, p_sdp );
psz_http_path = strdup("/"); if( p_sd )
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, "out of memory" ); sess_toitem ( p_intf, p_sd );
free( p_item ); free_sd ( p_sd );
return VLC_ENOMEM;
} }
sprintf( p_item->psz_uri, "%s://%s:%s%s", psz_proto,
psz_uri, psz_port,psz_http_path );
} }
/* 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 );
playlist_AddItem ( p_playlist, p_item,
PLAYLIST_CHECK_INSERT, PLAYLIST_END);
vlc_object_release( p_playlist );
}
if( psz_http_path )
free(psz_http_path);
} }
return VLC_SUCCESS;
} }
/********************************************************************** /**********************************************************************
...@@ -620,62 +434,132 @@ static void mfield_parse( char *psz_mfield, char **ppsz_proto, ...@@ -620,62 +434,132 @@ static void mfield_parse( char *psz_mfield, char **ppsz_proto,
return; return;
} }
/***********************************************************************
* parse_sap : Takes care of the SAP headers
***********************************************************************
* checks if the packet has the true headers ;
* returns the SAP header lenhth
***********************************************************************/
static int parse_sap( char *p_packet ) /*******************************************************************
* 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 )
{ {
// According to RFC 2974 playlist_item_t * p_item;
int i_hlen = 4; // Minimum header length is 4 char *psz_uri, *psz_proto;
i_hlen += (p_packet[0] & 0x10) ? 16 : 4; // Address type IPv6=16bytes char *psz_port;
i_hlen += p_packet[1]; // Authentification length char *psz_uri_default;
int i_count , i;
//Looks for the first '\0' byte after length vlc_bool_t b_http = VLC_FALSE;
for(;p_packet[i_hlen]!='\0'; i_hlen++); char *psz_http_path = NULL;
playlist_t *p_playlist;
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); 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++ )
* packet_handle : handle the received packet and enques the {
* the understated session 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( "" );
static int packet_handle( intf_thread_t * p_intf, char *p_packet, int i_len ) psz_uri = NULL;
{
sess_descr_t * p_sd;
int i_hlen; // Header length
i_hlen = parse_sap(p_packet); /* Build what we have to put in p_item->psz_uri, with the m and
* c fields */
if( (i_hlen > 0) && (i_hlen < i_len) ) if( !p_sd->pp_media[i_count] )
{
p_sd = parse_sdp( p_intf, p_packet + i_hlen +1);
if(p_sd)
{ {
sess_toitem ( p_intf, p_sd ); return;
free_sd ( p_sd );
return VLC_TRUE;
} }
}
return VLC_FALSE; // Invalid Packet mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
} & psz_proto, & psz_port );
if( !psz_proto || !psz_port )
{
return;
}
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;
}
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 */
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 * parse_sdp : SDP parsing
...@@ -686,189 +570,110 @@ static int packet_handle( intf_thread_t * p_intf, char *p_packet, int i_len ) ...@@ -686,189 +570,110 @@ 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 ) static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
{ {
sess_descr_t * sd; 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] != '=' ) if( p_packet[0] != 'v' || p_packet[1] != '=' )
{ {
msg_Warn( p_intf, "bad SDP packet %.2x%.2x", p_packet[0], p_packet[1] ); msg_Warn(p_intf, "bad SDP packet");
return NULL; return NULL;
} }
if( ( sd = malloc( sizeof(sess_descr_t) ) ) == NULL ) sd = malloc( sizeof( sess_descr_t ) );
{
msg_Err( p_intf, "out of memory for sd in parse_sdp()" );
return NULL;
}
sd->pp_media = NULL;
sd->pp_attributes = NULL;
sd->psz_origin = NULL;
sd->psz_sessionname = NULL; sd->psz_sessionname = NULL;
sd->psz_information = NULL; sd->psz_connection = NULL;
sd->psz_uri = NULL; sd->i_media = 0;
sd->psz_emails = NULL; sd->pp_media = NULL;
sd->psz_phone = NULL; sd->i_attributes = 0;
sd->psz_time = NULL; sd->pp_attributes = NULL;
sd->psz_repeat = NULL;
sd->psz_attribute = NULL;
sd->psz_connection = NULL;
sd->i_media = 0;
sd->i_attributes = 0;
while( *p_packet != '\0' ) while( *p_packet != '\0' )
{ {
#define FIELD_COPY( p ) \
p = strndup( &p_packet[2], i_field_len );
char *psz_end; char *psz_end;
int i_field_len;
/* Search begin of field */
while( *p_packet == '\n' || *p_packet == ' ' || *p_packet == '\t' ) while( *p_packet == '\n' || *p_packet == ' ' || *p_packet == '\t' )
{ {
p_packet++; p_packet++;
} }
if( *p_packet == '\0' ) /* search end of line */
if( ( psz_end = strchr( p_packet, '\n' ) ) == NULL )
{
psz_end = p_packet + strlen( p_packet );
}
if( psz_end <= p_packet )
{ {
break; break;
} }
*psz_end++ = '\0';
if( ( psz_end = strchr( p_packet, '\n' ) ) == NULL ) if( p_packet[1] != '=' )
{ {
psz_end = p_packet + strlen( p_packet ); msg_Warn( p_intf, "packet invalid" );
free_sd( sd );
return NULL;
} }
i_field_len = psz_end - &p_packet[2];
if( p_packet[1] == '=' && i_field_len > 0) switch( p_packet[0] )
{ {
switch( *p_packet ) 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' ):
{ {
case( 'v' ): char *psz_eof = strchr( &p_packet[2], ':' );
FIELD_COPY( sd->psz_version );
break; if( psz_eof && psz_eof[1] != '\0' )
case ( 'o' ): {
FIELD_COPY( sd->psz_origin ); attr_descr_t *attr = malloc( sizeof( attr_descr_t ) );
break;
case( 's' ): *psz_eof++ = '\0';
FIELD_COPY( sd->psz_sessionname );
break; attr->psz_field = strdup( &p_packet[2] );
case( 'i' ): attr->psz_value = strdup( psz_eof );
FIELD_COPY( sd->psz_information );
break; TAB_APPEND( sd->i_attributes, sd->pp_attributes, attr );
case( 'u' ): }
FIELD_COPY( sd->psz_uri ); break;
break; }
case( 'e' ):
FIELD_COPY( sd->psz_emails ); case( 'm' ):
break; {
case( 'p' ): media_descr_t *media = malloc( sizeof( media_descr_t ) );
FIELD_COPY( sd->psz_phone );
break; media->psz_medianame = strdup( &p_packet[2] );
case( 't' ): media->psz_mediaconnection = NULL;
FIELD_COPY( sd->psz_time );
break; TAB_APPEND( sd->i_media, sd->pp_media, media );
case( 'r' ): break;
FIELD_COPY( sd->psz_repeat );
break;
case( 'a' ):
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' ):
if( sd->pp_media )
{
sd->pp_media =
realloc( sd->pp_media,
sizeof( media_descr_t ) * ( sd->i_media + 1 ) );
}
else
{
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->i_media++;
break;
case( 'c' ):
if( sd->i_media <= 0 )
{
FIELD_COPY(sd->psz_connection);
}
else
{
FIELD_COPY(sd->pp_media[sd->i_media - 1]->psz_mediaconnection);
}
break;
default:
break;
} }
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; p_packet = psz_end;
#undef FIELD_COPY
} }
return sd; return sd;
...@@ -879,39 +684,24 @@ static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet ) ...@@ -879,39 +684,24 @@ static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
static void free_sd( sess_descr_t * p_sd ) static void free_sd( sess_descr_t * p_sd )
{ {
int i; 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 );
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 );
}
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 ); FREE( p_sd->psz_sessionname );
FREE( p_sd->psz_connection );
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 );
} }
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 );
} }
/*********************************************************************** /***********************************************************************
...@@ -928,26 +718,16 @@ static int ismult( char *psz_uri ) ...@@ -928,26 +718,16 @@ static int ismult( char *psz_uri )
/* IPv6 */ /* IPv6 */
if( psz_uri[0] == '[') if( psz_uri[0] == '[')
{ {
if( !strncasecmp( &psz_uri[1], "FF0" , 3) && if( strncasecmp( &psz_uri[1], "FF0" , 3) ||
!strncasecmp( &psz_uri[2], "FF0" , 3) ) strncasecmp( &psz_uri[2], "FF0" , 3))
{ return( VLC_TRUE );
return VLC_FALSE; else
} return( VLC_FALSE );
return VLC_TRUE;
}
if( *psz_end != '.' )
{
return VLC_FALSE;
} }
if( i_value < 224 ) if( *psz_end != '.' ) { return( VLC_FALSE ); }
{
return VLC_FALSE;
}
return VLC_TRUE; return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
} }
...@@ -958,39 +738,27 @@ static int ismult( char *psz_uri ) ...@@ -958,39 +738,27 @@ static int ismult( char *psz_uri )
* Taken from udp.c * Taken from udp.c
******************************************************************************/ ******************************************************************************/
static ssize_t NetRead( intf_thread_t *p_intf, static ssize_t NetRead( intf_thread_t *p_intf,
int i_handle, int i_handle_v6, int fd[2], uint8_t *p_buffer, int i_len )
byte_t *p_buffer, size_t i_len)
{ {
#ifdef UNDER_CE #ifdef UNDER_CE
return -1; return -1;
#else #else
struct timeval timeout; struct timeval timeout;
fd_set fds; fd_set fds;
int i_ret; int i_ret;
int i_max_handle; int i_handle_max = __MAX( fd[0], fd[1] );
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 */ /* Initialize file descriptor set */
FD_ZERO( &fds ); FD_ZERO( &fds );
if( i_handle > 0 ) FD_SET( i_handle, &fds ); if( fd[0] > 0 ) FD_SET( fd[0], &fds );
if( i_handle_v6 > 0 ) FD_SET( i_handle_v6, &fds); if( fd[1] > 0 ) FD_SET( fd[1], &fds );
/* We'll wait 0.5 second if nothing happens */ /* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 500000; timeout.tv_usec = 500000;
/* Find if some data is available */ /* Find if some data is available */
i_ret = select( i_max_handle + 1, &fds, NULL, NULL, &timeout ); i_ret = select( i_handle_max + 1, &fds, NULL, NULL, &timeout );
if( i_ret == -1 && errno != EINTR ) if( i_ret == -1 && errno != EINTR )
{ {
...@@ -998,31 +766,16 @@ static ssize_t NetRead( intf_thread_t *p_intf, ...@@ -998,31 +766,16 @@ static ssize_t NetRead( intf_thread_t *p_intf,
} }
else if( i_ret > 0 ) else if( i_ret > 0 )
{ {
/* Get the data */ if( fd[0] > 0 && FD_ISSET( fd[0], &fds ) )
if(i_handle >0)
{
if(FD_ISSET( i_handle, &fds ))
{
i_recv = recv( i_handle, p_buffer, i_len, 0 );
}
}
if(i_handle_v6 >0)
{ {
if(FD_ISSET( i_handle_v6, &fds )) return recv( fd[0], p_buffer, i_len, 0 );
{
i_recv = recv( i_handle_v6, p_buffer, i_len, 0 );
}
} }
else if( fd[1] > 0 && FD_ISSET( fd[1], &fds ) )
if( i_recv < 0 )
{ {
msg_Err( p_intf, "recv failed (%s)", strerror(errno) ); return recv( fd[1], p_buffer, i_len, 0 );
} }
return i_recv;
} }
return 0; return 0;
#endif #endif
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment