@ -81,20 +81,13 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
{
struct addrinfo hints = { 0 } , * res = 0 ;
int error ;
char sport [ 16 ] ;
const char * node = 0 , * service = " 0 " ;
char service [ 16 ] ;
if ( port > 0 ) {
snprintf ( sport , sizeof ( sport ) , " %d " , port ) ;
service = sport ;
}
if ( ( hostname ) & & ( hostname [ 0 ] ! = ' \0 ' ) & & ( hostname [ 0 ] ! = ' ? ' ) ) {
node = hostname ;
}
snprintf ( service , sizeof ( service ) , " %d " , port ) ;
hints . ai_socktype = type ;
hints . ai_family = family ;
hints . ai_flags = flags ;
if ( ( error = getaddrinfo ( nod e, service , & hints , & res ) ) ) {
hints . ai_flags = flags ;
if ( ( error = getaddrinfo ( hostname , service , & hints , & res ) ) ) {
res = NULL ;
av_log ( NULL , AV_LOG_ERROR , " rtp_resolve_host: %s \n " , gai_strerror ( error ) ) ;
}
@ -102,6 +95,26 @@ static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
return res ;
}
static int compare_addr ( const struct sockaddr_storage * a ,
const struct sockaddr_storage * b )
{
if ( a - > ss_family ! = b - > ss_family )
return 1 ;
if ( a - > ss_family = = AF_INET ) {
return ( ( ( const struct sockaddr_in * ) a ) - > sin_addr . s_addr ! =
( ( const struct sockaddr_in * ) b ) - > sin_addr . s_addr ) ;
}
# if defined(IPPROTO_IPV6)
if ( a - > ss_family = = AF_INET6 ) {
const uint8_t * s6_addr_a = ( ( const struct sockaddr_in6 * ) a ) - > sin6_addr . s6_addr ;
const uint8_t * s6_addr_b = ( ( const struct sockaddr_in6 * ) b ) - > sin6_addr . s6_addr ;
return memcmp ( s6_addr_a , s6_addr_b , 16 ) ;
}
# endif
return 1 ;
}
/**
* add option to url of the form :
* " http://host:port/path?option1=val1&option2=val2...
@ -124,9 +137,9 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const
static void build_udp_url ( char * buf , int buf_size ,
const char * hostname , int port ,
int ssm , const char * source_addr ,
int local_port , int ttl ,
int max_packet_size , int connect )
int max_packet_size , int connect ,
const char * sources )
{
ff_url_join ( buf , buf_size , " udp " , NULL , hostname , port , NULL ) ;
if ( local_port > = 0 )
@ -135,11 +148,11 @@ static void build_udp_url(char *buf, int buf_size,
url_add_option ( buf , buf_size , " ttl=%d " , ttl ) ;
if ( max_packet_size > = 0 )
url_add_option ( buf , buf_size , " pkt_size=%d " , max_packet_size ) ;
if ( ssm )
url_add_option ( buf , buf_size , " sources=%s " , source_addr ) ;
if ( connect )
url_add_option ( buf , buf_size , " connect=1 " ) ;
url_add_option ( buf , buf_size , " fifo_size=0 " ) ;
if ( sources & & sources [ 0 ] )
url_add_option ( buf , buf_size , " sources=%s " , sources ) ;
}
/**
@ -152,7 +165,7 @@ static void build_udp_url(char *buf, int buf_size,
* ' connect = 0 / 1 ' : do a connect ( ) on the UDP socket
* deprecated option :
* ' localport = n ' : set the local port to n
* ' ssm = ip ' : use ip as source - specific multicast addres s
* ' source s = ip [ , ip ] ' : list allowed source IP addresse s
*
* if rtcpport isn ' t set the rtcp port will be the rtp port + 1
* if local rtp port isn ' t set any available port will be used for the local
@ -166,11 +179,10 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
int rtp_port , rtcp_port ,
ttl , connect ,
local_rtp_port , local_rtcp_port , max_packet_size ;
char hostname [ 256 ] , source_ip [ 50 ] ;
char hostname [ 256 ] , sources [ 1024 ] = " " ;
char buf [ 1024 ] ;
char path [ 1024 ] ;
const char * p ;
struct addrinfo * sourceaddr ;
av_url_split ( NULL , 0 , NULL , 0 , hostname , sizeof ( hostname ) , & rtp_port ,
path , sizeof ( path ) , uri ) ;
@ -180,7 +192,6 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
local_rtp_port = - 1 ;
local_rtcp_port = - 1 ;
max_packet_size = - 1 ;
s - > ssm = 0 ;
connect = 0 ;
p = strchr ( uri , ' ? ' ) ;
@ -206,30 +217,35 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
if ( av_find_info_tag ( buf , sizeof ( buf ) , " connect " , p ) ) {
connect = strtol ( buf , NULL , 10 ) ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " ssm " , p ) ) {
s - > ssm = 1 ;
snprintf ( source_ip , sizeof ( source_ip ) , " %s " , buf ) ;
sourceaddr = rtp_resolve_host ( source_ip , 0 ,
SOCK_DGRAM , AF_UNSPEC ,
AI_NUMERICHOST ) ;
memcpy ( & s - > ssm_addr , sourceaddr - > ai_addr , sourceaddr - > ai_addrlen ) ;
freeaddrinfo ( sourceaddr ) ;
if ( av_find_info_tag ( buf , sizeof ( buf ) , " sources " , p ) ) {
struct addrinfo * sourceaddr = NULL ;
av_strlcpy ( sources , buf , sizeof ( sources ) ) ;
/* Try resolving the IP if only one IP is specified - we don't
* support manually checking more than one IP . */
if ( ! strchr ( sources , ' , ' ) )
sourceaddr = rtp_resolve_host ( sources , 0 ,
SOCK_DGRAM , AF_UNSPEC ,
AI_NUMERICHOST ) ;
if ( sourceaddr ) {
s - > ssm = 1 ;
memcpy ( & s - > ssm_addr , sourceaddr - > ai_addr , sourceaddr - > ai_addrlen ) ;
freeaddrinfo ( sourceaddr ) ;
}
}
}
build_udp_url ( buf , sizeof ( buf ) ,
hostname , rtp_port , s - > ssm , source_ip , local_rtp_port , ttl , max_packet_size ,
connect ) ;
hostname , rtp_port , local_rtp_port , ttl , max_packet_size ,
connect , sources ) ;
if ( ffurl_open ( & s - > rtp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
goto fail ;
if ( local_rtp_port > = 0 & & local_rtcp_port < 0 )
local_rtcp_port = ff_udp_get_local_port ( s - > rtp_hd ) + 1 ;
build_udp_url ( buf , sizeof ( buf ) ,
hostname , rtcp_port , s - > ssm , source_ip , local_rtcp_port , ttl , max_packet_size ,
connect ) ;
hostname , rtcp_port , local_rtcp_port , ttl , max_packet_size ,
connect , sources ) ;
if ( ffurl_open ( & s - > rtcp_hd , buf , flags , & h - > interrupt_callback , NULL ) < 0 )
goto fail ;
@ -275,27 +291,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue ;
return AVERROR ( EIO ) ;
}
if ( s - > ssm ) {
if ( from . ss_family = = AF_INET & & s - > ssm_addr . ss_family = = AF_INET ) {
uint32_t intended_source = ( ( struct sockaddr_in * ) & s - > ssm_addr ) - > sin_addr . s_addr ;
uint32_t actual_source = ( ( struct sockaddr_in * ) & from ) - > sin_addr . s_addr ;
if ( intended_source ! = actual_source ) {
// discard the packet without any processing
continue ;
}
}
# if defined(IPPROTO_IPV6)
if ( from . ss_family = = AF_INET6 & & s - > ssm_addr . ss_family = = AF_INET6 ) {
unsigned char * intended_source = ( ( struct sockaddr_in6 * ) & s - > ssm_addr ) - > sin6_addr . s6_addr ;
unsigned char * actual_source = ( ( struct sockaddr_in6 * ) & from ) - > sin6_addr . s6_addr ;
if ( memcmp ( intended_source , actual_source , 16 ) ! = 0 ) {
// discard the packet without any processing
continue ;
}
}
# endif
}
if ( s - > ssm & & compare_addr ( & from , & s - > ssm_addr ) )
continue ;
break ;
}
/* then RTP */
@ -309,27 +306,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue ;
return AVERROR ( EIO ) ;
}
if ( s - > ssm ) {
if ( from . ss_family = = AF_INET & & s - > ssm_addr . ss_family = = AF_INET ) {
uint32_t intended_source = ( ( struct sockaddr_in * ) & s - > ssm_addr ) - > sin_addr . s_addr ;
uint32_t actual_source = ( ( struct sockaddr_in * ) & from ) - > sin_addr . s_addr ;
if ( intended_source ! = actual_source ) {
// discard the packet without any processing
continue ;
}
}
# if defined(IPPROTO_IPV6)
if ( from . ss_family = = AF_INET6 & & s - > ssm_addr . ss_family = = AF_INET6 ) {
unsigned char * intended_source = ( ( struct sockaddr_in6 * ) & s - > ssm_addr ) - > sin6_addr . s6_addr ;
unsigned char * actual_source = ( ( struct sockaddr_in6 * ) & from ) - > sin6_addr . s6_addr ;
if ( memcmp ( intended_source , actual_source , 16 ) ! = 0 ) {
// discard the packet without any processing
continue ;
}
}
# endif
}
if ( s - > ssm & & compare_addr ( & from , & s - > ssm_addr ) )
continue ;
break ;
}
} else if ( n < 0 ) {