@ -45,6 +45,9 @@ typedef struct RTPContext {
URLContext * rtp_hd , * rtcp_hd ;
int rtp_fd , rtcp_fd , nb_ssm_include_addrs , nb_ssm_exclude_addrs ;
struct sockaddr_storage * * ssm_include_addrs , * * ssm_exclude_addrs ;
int write_to_source ;
struct sockaddr_storage last_rtp_source , last_rtcp_source ;
socklen_t last_rtp_source_len , last_rtcp_source_len ;
} RTPContext ;
/**
@ -125,6 +128,27 @@ static int compare_addr(const struct sockaddr_storage *a,
return 1 ;
}
static int get_port ( const struct sockaddr_storage * ss )
{
if ( ss - > ss_family = = AF_INET )
return ntohs ( ( ( const struct sockaddr_in * ) ss ) - > sin_port ) ;
# ifdef AF_INET6
if ( ss - > ss_family = = AF_INET6 )
return ntohs ( ( ( const struct sockaddr_in6 * ) ss ) - > sin6_port ) ;
# endif
return 0 ;
}
static void set_port ( struct sockaddr_storage * ss , int port )
{
if ( ss - > ss_family = = AF_INET )
( ( struct sockaddr_in * ) ss ) - > sin_port = htons ( port ) ;
# ifdef AF_INET6
else if ( ss - > ss_family = = AF_INET6 )
( ( struct sockaddr_in6 * ) ss ) - > sin6_port = htons ( port ) ;
# endif
}
static int rtp_check_source_lists ( RTPContext * s , struct sockaddr_storage * source_addr_ptr )
{
int i ;
@ -237,6 +261,7 @@ static void rtp_parse_addr_list(URLContext *h, char *buf,
* ' connect = 0 / 1 ' : do a connect ( ) on the UDP socket
* ' sources = ip [ , ip ] ' : list allowed source IP addresses
* ' block = ip [ , ip ] ' : list disallowed source IP addresses
* ' write_to_source = 0 / 1 ' : send packets to the source address of the latest received packet
* deprecated option :
* ' localport = n ' : set the local port to n
*
@ -290,6 +315,9 @@ 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 ) , " write_to_source " , p ) ) {
s - > write_to_source = strtol ( buf , NULL , 10 ) ;
}
if ( av_find_info_tag ( buf , sizeof ( buf ) , " sources " , p ) ) {
av_strlcpy ( include_sources , buf , sizeof ( include_sources ) ) ;
rtp_parse_addr_list ( h , buf , & s - > ssm_include_addrs , & s - > nb_ssm_include_addrs ) ;
@ -334,11 +362,11 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
static int rtp_read ( URLContext * h , uint8_t * buf , int size )
{
RTPContext * s = h - > priv_data ;
struct sockaddr_storage from ;
socklen_t from_len ;
int len , n , i ;
struct pollfd p [ 2 ] = { { s - > rtp_fd , POLLIN , 0 } , { s - > rtcp_fd , POLLIN , 0 } } ;
int poll_delay = h - > flags & AVIO_FLAG_NONBLOCK ? 0 : 100 ;
struct sockaddr_storage * addrs [ 2 ] = { & s - > last_rtp_source , & s - > last_rtcp_source } ;
socklen_t * addr_lens [ 2 ] = { & s - > last_rtp_source_len , & s - > last_rtcp_source_len } ;
for ( ; ; ) {
if ( ff_check_interrupt ( & h - > interrupt_callback ) )
@ -349,16 +377,16 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
for ( i = 1 ; i > = 0 ; i - - ) {
if ( ! ( p [ i ] . revents & POLLIN ) )
continue ;
from_len = sizeof ( from ) ;
* addr_lens [ i ] = sizeof ( * addrs [ i ] ) ;
len = recvfrom ( p [ i ] . fd , buf , size , 0 ,
( struct sockaddr * ) & from , & from_len ) ;
( struct sockaddr * ) addrs [ i ] , addr_lens [ i ] ) ;
if ( len < 0 ) {
if ( ff_neterrno ( ) = = AVERROR ( EAGAIN ) | |
ff_neterrno ( ) = = AVERROR ( EINTR ) )
continue ;
return AVERROR ( EIO ) ;
}
if ( rtp_check_source_lists ( s , & from ) )
if ( rtp_check_source_lists ( s , addrs [ i ] ) )
continue ;
return len ;
}
@ -382,6 +410,57 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
if ( size < 2 )
return AVERROR ( EINVAL ) ;
if ( s - > write_to_source ) {
int fd ;
struct sockaddr_storage * source , temp_source ;
socklen_t * source_len , temp_len ;
if ( ! s - > last_rtp_source . ss_family & & ! s - > last_rtcp_source . ss_family ) {
av_log ( h , AV_LOG_ERROR ,
" Unable to send packet to source, no packets received yet \n " ) ;
// Intentionally not returning an error here
return size ;
}
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
fd = s - > rtcp_fd ;
source = & s - > last_rtcp_source ;
source_len = & s - > last_rtcp_source_len ;
} else {
fd = s - > rtp_fd ;
source = & s - > last_rtp_source ;
source_len = & s - > last_rtp_source_len ;
}
if ( ! source - > ss_family ) {
source = & temp_source ;
source_len = & temp_len ;
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
temp_source = s - > last_rtp_source ;
temp_len = s - > last_rtp_source_len ;
set_port ( source , get_port ( source ) + 1 ) ;
av_log ( h , AV_LOG_INFO ,
" Not received any RTCP packets yet, inferring peer port "
" from the RTP port \n " ) ;
} else {
temp_source = s - > last_rtcp_source ;
temp_len = s - > last_rtcp_source_len ;
set_port ( source , get_port ( source ) - 1 ) ;
av_log ( h , AV_LOG_INFO ,
" Not received any RTP packets yet, inferring peer port "
" from the RTCP port \n " ) ;
}
}
if ( ! ( h - > flags & AVIO_FLAG_NONBLOCK ) ) {
ret = ff_network_wait_fd ( fd , 1 ) ;
if ( ret < 0 )
return ret ;
}
ret = sendto ( fd , buf , size , 0 , ( struct sockaddr * ) source ,
* source_len ) ;
return ret < 0 ? ff_neterrno ( ) : ret ;
}
if ( RTP_PT_IS_RTCP ( buf [ 1 ] ) ) {
/* RTCP payload type */
hd = s - > rtcp_hd ;