@ -1479,9 +1479,7 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out
goto output ;
if ( PS_ISSET2 ( stream , STRICT_SOURCE , MEDIA_HANDOVER ) ) {
mutex_lock ( & stream - > out_lock ) ;
__re_address_translate_ep ( & reti - > expected_src , MEDIA_ISSET ( media , ASYMMETRIC ) ? & stream - > learned_endpoint : & stream - > endpoint ) ;
mutex_unlock ( & stream - > out_lock ) ;
if ( PS_ISSET ( stream , STRICT_SOURCE ) )
reti - > src_mismatch = MSM_DROP ;
else if ( PS_ISSET ( stream , MEDIA_HANDOVER ) )
@ -1620,7 +1618,12 @@ output:
reti - > pt_filter = 1 ;
}
mutex_lock ( & sink - > out_lock ) ;
/ / XXX nested lock , avoid possible deadlock . should be reworked not to
/ / require a nested lock
if ( sink ! = stream & & mutex_trylock ( & sink - > lock ) ) {
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
return " " ; / / indicate deadlock
}
__re_address_translate_ep ( & redi - > output . dst_addr , & sink - > endpoint ) ;
__re_address_translate_ep ( & redi - > output . src_addr , & sink - > selected_sfd - > socket . local ) ;
@ -1642,7 +1645,8 @@ output:
handler - > out - > kernel ( & redi - > output . encrypt , sink ) ;
mutex_unlock ( & sink - > out_lock ) ;
if ( sink ! = stream )
mutex_unlock ( & sink - > lock ) ;
if ( ! redi - > output . encrypt . cipher | | ! redi - > output . encrypt . hmac ) {
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
@ -1659,32 +1663,39 @@ output:
return NULL ;
}
/ / helper function for kernelize ( )
static void kernelize_one_sink_handler ( struct rtpengine_target_info * reti , GQueue * outputs ,
static bool kernelize_one_sink_handler ( struct rtpengine_target_info * reti , GQueue * outputs ,
struct packet_stream * stream , struct sink_handler * sink_handler , sink_handler_q * sinks ,
GList * * payload_types )
{
struct packet_stream * sink = sink_handler - > sink ;
if ( PS_ISSET ( sink , NAT_WAIT ) & & ! PS_ISSET ( sink , RECEIVED ) )
return ;
return true ;
const char * err = kernelize_one ( reti , outputs , stream , sink_handler , & stream - > rtp_sinks ,
payload_types ) ;
if ( err )
if ( err ) {
if ( ! * err )
return false ; / / indicate deadlock
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , err ) ;
}
return true ;
}
/* called with in_lock held */
void kernelize ( struct packet_stream * stream ) {
/* called with master _lock held */
static void kernelize ( struct packet_stream * stream ) {
call_t * call = stream - > call ;
const char * nk_warn_msg ;
struct call_media * media = stream - > media ;
if ( PS_ISSET ( stream , KERNELIZED ) )
while ( true ) {
LOCK ( & stream - > lock ) ;
/ / set flag , return if set already
if ( PS_SET ( stream , KERNELIZED ) )
return ;
if ( call - > recording ! = NULL & & ! selected_recording_method - > kernel_support )
goto no_kernel ;
if ( ! kernel . is_wanted )
goto no_kernel ;
nk_warn_msg = " interface to kernel module not open " ;
if ( ! kernel . is_open )
goto no_kernel_warn ;
if ( MEDIA_ISSET ( media , GENERATOR ) )
@ -1706,27 +1717,36 @@ void kernelize(struct packet_stream *stream) {
if ( num_sinks = = 0 ) {
/ / add blackhole kernel rule
const char * err = kernelize_one ( & reti , & outputs , stream , NULL , NULL , & payload_types ) ;
if ( err )
if ( err ) {
if ( ! * err )
goto restart ;
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , err ) ;
}
}
else {
for ( __auto_type l = stream - > rtp_sinks . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
if ( sh - > attrs . block_media )
continue ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
& payload_types ) ;
if ( ! ok )
goto restart ;
}
for ( __auto_type l = stream - > rtp_mirrors . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
& payload_types ) ;
if ( ! ok )
goto restart ;
}
/ / record number of RTP destinations
unsigned int num_rtp_dests = reti . num_destinations ;
for ( __auto_type l = stream - > rtcp_sinks . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks , NULL ) ;
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks , NULL ) ;
if ( ! ok )
goto restart ;
}
reti . num_rtcp_destinations = reti . num_destinations - num_rtp_dests ;
}
@ -1750,15 +1770,25 @@ void kernelize(struct packet_stream *stream) {
}
stream - > kernel_time = rtpe_now . tv_sec ;
PS_SET ( stream , KERNELIZED ) ;
return ;
no_kernel_warn :
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , nk_warn_msg ) ;
ilog ( LOG_WARNING , " No support for kernel packet forwarding available "
" (interface to kernel module not open) " ) ;
no_kernel :
PS_SET ( stream , KERNELIZED ) ;
stream - > kernel_time = rtpe_now . tv_sec ;
PS_SET ( stream , NO_KERNEL_SUPPORT ) ;
return ;
restart : / / handle detected deadlock
g_list_free ( payload_types ) ;
while ( ( redi = g_queue_pop_head ( & outputs ) ) )
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
/ / try again , releases stream - > lock
}
}
/ / must be called with appropriate locks ( master lock and / or in / out_lock )
@ -1787,7 +1817,7 @@ struct ssrc_ctx *__hunt_ssrc_ctx(uint32_t ssrc, struct ssrc_ctx *list[RTPE_NUM_S
}
/* must be called with in_ lock held or call->master_lock held in W */
/* must be called with ps-> lock held or call->master_lock held in W */
void __unkernelize ( struct packet_stream * p , const char * reason ) {
if ( ! p - > selected_sfd )
return ;
@ -1833,9 +1863,8 @@ void __stream_unconfirm(struct packet_stream *ps, const char *reason) {
static void stream_unconfirm ( struct packet_stream * ps , const char * reason ) {
if ( ! ps )
return ;
mutex_lock ( & ps - > in_ lock) ;
LOCK ( & ps - > lock ) ;
__stream_unconfirm ( ps , reason ) ;
mutex_unlock ( & ps - > in_lock ) ;
}
static void unconfirm_sinks ( sink_handler_q * q , const char * reason ) {
for ( __auto_type l = q - > head ; l ; l = l - > next ) {
@ -1846,9 +1875,8 @@ static void unconfirm_sinks(sink_handler_q *q, const char *reason) {
void unkernelize ( struct packet_stream * ps , const char * reason ) {
if ( ! ps )
return ;
mutex_lock ( & ps - > in_ lock) ;
LOCK ( & ps - > lock ) ;
__unkernelize ( ps , reason ) ;
mutex_unlock ( & ps - > in_lock ) ;
}
@ -1885,7 +1913,7 @@ err:
return & __sh_noop ;
}
/* must be called with call->master_lock held in R, and in->in_ lock held */
/* must be called with call->master_lock held in R, and in->lock held */
/ / ` sh ` can be null
static const struct streamhandler * __determine_handler ( struct packet_stream * in , struct sink_handler * sh ) {
const struct transport_protocol * in_proto , * out_proto ;
@ -1994,7 +2022,7 @@ static const char *__stream_ssrc_inout(struct packet_stream *ps, uint32_t ssrc,
static const char * __stream_ssrc_in ( struct packet_stream * in_srtp , uint32_t ssrc_bs ,
struct ssrc_ctx * * ssrc_in_p , struct ssrc_hash * ssrc_hash )
{
return __stream_ssrc_inout ( in_srtp , ntohl ( ssrc_bs ) , & in_srtp - > in_ lock, in_srtp - > ssrc_in ,
return __stream_ssrc_inout ( in_srtp , ntohl ( ssrc_bs ) , & in_srtp - > lock , in_srtp - > ssrc_in ,
& in_srtp - > ssrc_in_idx , 0 , ssrc_in_p , ssrc_hash , SSRC_DIR_INPUT , " ingress " ) ;
}
/ / check and update output SSRC pointers
@ -2004,12 +2032,12 @@ static const char *__stream_ssrc_out(struct packet_stream *out_srtp, uint32_t ss
bool ssrc_change )
{
if ( ssrc_change )
return __stream_ssrc_inout ( out_srtp , ssrc_in - > ssrc_map_out , & out_srtp - > out_ lock,
return __stream_ssrc_inout ( out_srtp , ssrc_in - > ssrc_map_out , & out_srtp - > lock ,
out_srtp - > ssrc_out ,
& out_srtp - > ssrc_out_idx , ntohl ( ssrc_bs ) , ssrc_out_p , ssrc_hash , SSRC_DIR_OUTPUT ,
" egress (mapped) " ) ;
return __stream_ssrc_inout ( out_srtp , ntohl ( ssrc_bs ) , & out_srtp - > out_ lock,
return __stream_ssrc_inout ( out_srtp , ntohl ( ssrc_bs ) , & out_srtp - > lock ,
out_srtp - > ssrc_out ,
& out_srtp - > ssrc_out_idx , 0 , ssrc_out_p , ssrc_hash , SSRC_DIR_OUTPUT ,
" egress (direct) " ) ;
@ -2034,14 +2062,13 @@ static int media_demux_protocols(struct packet_handler_ctx *phc) {
}
}
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
LOCK ( & phc - > mp . stream - > lock ) ;
int ret = dtls ( phc - > mp . sfd , & phc - > s , & phc - > mp . fsin ) ;
if ( ret = = 1 ) {
phc - > unkernelize = " DTLS connected " ;
phc - > unkernelize_subscriptions = true ;
ret = 0 ;
}
mutex_unlock ( & phc - > mp . stream - > in_lock ) ;
if ( ! ret )
return 0 ;
}
@ -2066,7 +2093,7 @@ static int media_demux_protocols(struct packet_handler_ctx *phc) {
# if RTP_LOOP_PROTECT
/ / returns : 0 = ok , proceed ; - 1 = duplicate detected , drop packet
static int media_loop_detect ( struct packet_handler_ctx * phc ) {
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
mutex_lock ( & phc - > mp . stream - > lock ) ;
for ( int i = 0 ; i < RTP_LOOP_PACKETS ; i + + ) {
if ( phc - > mp . stream - > lp_buf [ i ] . len ! = phc - > s . len )
@ -2080,7 +2107,7 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
" to avoid potential loop " ,
RTP_LOOP_MAX_COUNT ,
FMT_M ( endpoint_print_buf ( & phc - > mp . fsin ) ) ) ;
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock ) ;
return - 1 ;
}
@ -2094,7 +2121,7 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
memcpy ( phc - > mp . stream - > lp_buf [ phc - > mp . stream - > lp_idx ] . buf , phc - > s . s , MIN ( phc - > s . len , RTP_LOOP_PROTECT ) ) ;
phc - > mp . stream - > lp_idx = ( phc - > mp . stream - > lp_idx + 1 ) % RTP_LOOP_PACKETS ;
loop_ok :
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock ) ;
return 0 ;
}
@ -2213,7 +2240,7 @@ static void media_packet_rtp_out(struct packet_handler_ctx *phc, struct sink_han
static int media_packet_decrypt ( struct packet_handler_ctx * phc )
{
mutex_lock ( & phc - > in_srtp - > in_ lock) ;
mutex_lock ( & phc - > in_srtp - > lock ) ;
struct sink_handler * first_sh = phc - > sinks - > length ? phc - > sinks - > head - > data : NULL ;
const struct streamhandler * sh = __determine_handler ( phc - > in_srtp , first_sh ) ;
@ -2234,7 +2261,7 @@ static int media_packet_decrypt(struct packet_handler_ctx *phc)
phc - > mp . payload . len - = ori_s . len - phc - > s . len ;
}
mutex_unlock ( & phc - > in_srtp - > in_ lock) ;
mutex_unlock ( & phc - > in_srtp - > lock ) ;
if ( ret = = 1 ) {
phc - > update = true ;
@ -2244,7 +2271,7 @@ static int media_packet_decrypt(struct packet_handler_ctx *phc)
}
static void media_packet_set_encrypt ( struct packet_handler_ctx * phc , struct sink_handler * sh )
{
mutex_lock ( & phc - > in_srtp - > in_ lock) ;
mutex_lock ( & phc - > in_srtp - > lock ) ;
__determine_handler ( phc - > in_srtp , sh ) ;
/ / XXX use an array with index instead of if / else
@ -2254,7 +2281,7 @@ static void media_packet_set_encrypt(struct packet_handler_ctx *phc, struct sink
phc - > encrypt_func = sh - > handler - > out - > rtcp_crypt ;
phc - > rtcp_filter = sh - > handler - > in - > rtcp_filter ;
}
mutex_unlock ( & phc - > in_srtp - > in_ lock) ;
mutex_unlock ( & phc - > in_srtp - > lock ) ;
}
int media_packet_encrypt ( rewrite_func encrypt_func , struct packet_stream * out , struct media_packet * mp ) {
@ -2263,7 +2290,7 @@ int media_packet_encrypt(rewrite_func encrypt_func, struct packet_stream *out, s
if ( ! encrypt_func )
return 0x00 ;
mutex_lock ( & out - > out_ lock) ;
LOCK ( & out - > lock ) ;
for ( __auto_type l = mp - > packets_out . head ; l ; l = l - > next ) {
struct codec_packet * p = l - > data ;
@ -2280,8 +2307,6 @@ int media_packet_encrypt(rewrite_func encrypt_func, struct packet_stream *out, s
ret | = 0x01 ;
}
mutex_unlock ( & out - > out_lock ) ;
return ret ;
}
@ -2301,7 +2326,7 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
struct endpoint endpoint ;
bool ret = false ;
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
mutex_lock ( & phc - > mp . stream - > lock ) ;
/* we're OK to (potentially) use the source address of this packet as destination
* in the other direction . */
@ -2330,10 +2355,8 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
/* do not pay attention to source addresses of incoming packets for asymmetric streams */
if ( MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) | | phc - > mp . stream - > el_flags = = EL_OFF ) {
PS_SET ( phc - > mp . stream , CONFIRMED ) ;
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
if ( MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) & & ! phc - > mp . stream - > learned_endpoint . address . family )
phc - > mp . stream - > learned_endpoint = phc - > mp . fsin ;
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
}
/* confirm sinks for unidirectional streams in order to kernelize */
@ -2349,7 +2372,6 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
/* see if we need to compare the source address with the known endpoint */
if ( PS_ISSET2 ( phc - > mp . stream , STRICT_SOURCE , MEDIA_HANDOVER ) ) {
endpoint = phc - > mp . fsin ;
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
struct endpoint * ps_endpoint = MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) ?
& phc - > mp . stream - > learned_endpoint : & phc - > mp . stream - > endpoint ;
@ -2365,8 +2387,6 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
goto update_addr ;
}
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
if ( tmp & & PS_ISSET ( phc - > mp . stream , STRICT_SOURCE ) ) {
ilog ( LOG_INFO | LOG_FLAG_LIMIT , " Drop due to strict-source attribute; "
" got %s%s:%d%s, "
@ -2440,7 +2460,6 @@ confirm_now:
PS_SET ( phc - > mp . stream , CONFIRMED ) ;
update_peerinfo :
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
/ / if we ' re during the wait time , check the received address against the previously
/ / learned address . if they ' re the same , ignore this packet for learning purposes
if ( ! wait_time | | ! phc - > mp . stream - > learned_endpoint . address . family | |
@ -2459,8 +2478,6 @@ update_peerinfo:
}
}
update_addr :
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
/* check the destination address of the received packet against what we think our
* local interface to use is */
if ( phc - > mp . stream - > selected_sfd & & phc - > mp . sfd ! = phc - > mp . stream - > selected_sfd ) {
@ -2483,7 +2500,7 @@ update_addr:
}
out :
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock ) ;
return ret ;
}
@ -2503,9 +2520,7 @@ static void media_packet_kernel_check(struct packet_handler_ctx *phc) {
if ( ML_ISSET ( phc - > mp . media - > monologue , DTMF_INJECTION_ACTIVE ) )
return ;
mutex_lock ( & phc - > mp . stream - > in_lock ) ;
kernelize ( phc - > mp . stream ) ;
mutex_unlock ( & phc - > mp . stream - > in_lock ) ;
}
@ -2842,19 +2857,19 @@ static int stream_packet(struct packet_handler_ctx *phc) {
if ( ret )
goto next_mirror ;
mutex_lock ( & mirror_sink - > out_ lock) ;
mutex_lock ( & mirror_sink - > lock ) ;
if ( ! mirror_sink - > advertised_endpoint . port
| | ( is_addr_unspecified ( & mirror_sink - > advertised_endpoint . address )
& & ! is_trickle_ice_address ( & mirror_sink - > advertised_endpoint ) ) )
{
mutex_unlock ( & mirror_sink - > out_ lock) ;
mutex_unlock ( & mirror_sink - > lock ) ;
goto next_mirror ;
}
media_socket_dequeue ( & mirror_phc . mp , mirror_sink ) ;
mutex_unlock ( & mirror_sink - > out_ lock) ;
mutex_unlock ( & mirror_sink - > lock ) ;
next_mirror :
media_socket_dequeue ( & mirror_phc . mp , NULL ) ; / / just free if anything left
@ -2867,13 +2882,13 @@ next_mirror:
if ( ret = = - 1 )
goto err_next ;
mutex_lock ( & sink - > out_ lock) ;
mutex_lock ( & sink - > lock ) ;
if ( ! sink - > advertised_endpoint . port
| | ( is_addr_unspecified ( & sink - > advertised_endpoint . address )
& & ! is_trickle_ice_address ( & sink - > advertised_endpoint ) ) )
{
mutex_unlock ( & sink - > out_ lock) ;
mutex_unlock ( & sink - > lock ) ;
goto next ;
}
@ -2882,7 +2897,7 @@ next_mirror:
else
ret = media_socket_dequeue ( & phc - > mp , NULL ) ;
mutex_unlock ( & sink - > out_ lock) ;
mutex_unlock ( & sink - > lock ) ;
if ( ret = = 0 )
goto next ;
@ -2890,10 +2905,10 @@ next_mirror:
err_next :
ilog ( LOG_DEBUG | LOG_FLAG_LIMIT , " Error when sending message. Error: %s " , strerror ( errno ) ) ;
atomic64_inc_na ( & sink - > stats_in - > errors ) ;
mutex_lock ( & sink - > in_ lock) ;
mutex_lock ( & sink - > lock ) ;
if ( sink - > selected_sfd )
atomic64_inc_na ( & sink - > selected_sfd - > local_intf - > stats - > out . errors ) ;
mutex_unlock ( & sink - > in_ lock) ;
mutex_unlock ( & sink - > lock ) ;
RTPE_STATS_INC ( errors_user ) ;
goto next ;