|
|
|
@ -60,13 +60,7 @@ struct intf_rr { |
|
|
|
struct packet_handler_ctx { |
|
|
|
// inputs: |
|
|
|
str s; // raw input packet |
|
|
|
endpoint_t fsin; // source address of received packet |
|
|
|
struct timeval tv; // timestamp when packet was received |
|
|
|
struct stream_fd *sfd; // fd which received the packet |
|
|
|
|
|
|
|
struct call *call; // sfd->call |
|
|
|
struct packet_stream *stream; // sfd->stream |
|
|
|
struct call_media *media; // stream->media |
|
|
|
struct packet_stream *sink; // where to send output packets to (forward destination) |
|
|
|
rewrite_func decrypt_func, encrypt_func; // handlers for decrypt/encrypt |
|
|
|
rtcp_filter_func *rtcp_filter; |
|
|
|
@ -1136,31 +1130,38 @@ noop: |
|
|
|
static void __stream_ssrc(struct packet_stream *in_srtp, struct packet_stream *out_srtp, u_int32_t ssrc_bs, |
|
|
|
struct ssrc_ctx **ssrc_in_p, struct ssrc_ctx **ssrc_out_p, struct ssrc_hash *ssrc_hash) |
|
|
|
{ |
|
|
|
u_int32_t ssrc = ntohl(ssrc_bs); |
|
|
|
u_int32_t in_ssrc = ntohl(ssrc_bs); |
|
|
|
u_int32_t out_ssrc; |
|
|
|
|
|
|
|
// input direction |
|
|
|
mutex_lock(&in_srtp->in_lock); |
|
|
|
|
|
|
|
(*ssrc_in_p) = in_srtp->ssrc_in; |
|
|
|
if (G_UNLIKELY(!(*ssrc_in_p) || (*ssrc_in_p)->parent->h.ssrc != ssrc)) { |
|
|
|
if (G_UNLIKELY(!(*ssrc_in_p) || (*ssrc_in_p)->parent->h.ssrc != in_ssrc)) { |
|
|
|
// SSRC mismatch - get the new entry |
|
|
|
(*ssrc_in_p) = in_srtp->ssrc_in = |
|
|
|
get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_INPUT); |
|
|
|
get_ssrc_ctx(in_ssrc, ssrc_hash, SSRC_DIR_INPUT); |
|
|
|
|
|
|
|
// might have created a new entry, which would have a new random |
|
|
|
// ssrc_map_out. we don't need this if we're not transcoding |
|
|
|
if (!MEDIA_ISSET(in_srtp->media, TRANSCODE)) |
|
|
|
(*ssrc_in_p)->ssrc_map_out = in_ssrc; |
|
|
|
} |
|
|
|
|
|
|
|
mutex_unlock(&in_srtp->in_lock); |
|
|
|
|
|
|
|
if (MEDIA_ISSET(in_srtp->media, TRANSCODE)) |
|
|
|
ssrc = (*ssrc_in_p)->ssrc_map_out; |
|
|
|
|
|
|
|
// out direction |
|
|
|
out_ssrc = (*ssrc_in_p)->ssrc_map_out; |
|
|
|
mutex_lock(&out_srtp->out_lock); |
|
|
|
|
|
|
|
(*ssrc_out_p) = out_srtp->ssrc_out; |
|
|
|
if (G_UNLIKELY(!(*ssrc_out_p) || (*ssrc_out_p)->parent->h.ssrc != ssrc)) { |
|
|
|
if (G_UNLIKELY(!(*ssrc_out_p) || (*ssrc_out_p)->parent->h.ssrc != out_ssrc)) { |
|
|
|
// SSRC mismatch - get the new entry |
|
|
|
(*ssrc_out_p) = out_srtp->ssrc_out = |
|
|
|
get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_OUTPUT); |
|
|
|
get_ssrc_ctx(out_ssrc, ssrc_hash, SSRC_DIR_OUTPUT); |
|
|
|
|
|
|
|
// reverse SSRC mapping |
|
|
|
(*ssrc_out_p)->ssrc_map_out = in_ssrc; |
|
|
|
} |
|
|
|
|
|
|
|
mutex_unlock(&out_srtp->out_lock); |
|
|
|
@ -1170,20 +1171,20 @@ static void __stream_ssrc(struct packet_stream *in_srtp, struct packet_stream *o |
|
|
|
// returns: 0 = packet processed by other protocol hander; -1 = packet not handled, proceed; |
|
|
|
// 1 = same as 0, but stream can be kernelized |
|
|
|
static int media_demux_protocols(struct packet_handler_ctx *phc) { |
|
|
|
if (MEDIA_ISSET(phc->media, DTLS) && is_dtls(&phc->s)) { |
|
|
|
mutex_lock(&phc->stream->in_lock); |
|
|
|
int ret = dtls(phc->stream, &phc->s, &phc->fsin); |
|
|
|
mutex_unlock(&phc->stream->in_lock); |
|
|
|
if (MEDIA_ISSET(phc->mp.media, DTLS) && is_dtls(&phc->s)) { |
|
|
|
mutex_lock(&phc->mp.stream->in_lock); |
|
|
|
int ret = dtls(phc->mp.stream, &phc->s, &phc->mp.fsin); |
|
|
|
mutex_unlock(&phc->mp.stream->in_lock); |
|
|
|
if (!ret) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (phc->media->ice_agent && is_stun(&phc->s)) { |
|
|
|
int stun_ret = stun(&phc->s, phc->sfd, &phc->fsin); |
|
|
|
if (phc->mp.media->ice_agent && is_stun(&phc->s)) { |
|
|
|
int stun_ret = stun(&phc->s, phc->mp.sfd, &phc->mp.fsin); |
|
|
|
if (!stun_ret) |
|
|
|
return 0; |
|
|
|
if (stun_ret == 1) { |
|
|
|
call_media_state_machine(phc->media); |
|
|
|
call_media_state_machine(phc->mp.media); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
else /* not an stun packet */ |
|
|
|
@ -1197,33 +1198,33 @@ 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->stream->in_lock); |
|
|
|
mutex_lock(&phc->mp.stream->in_lock); |
|
|
|
|
|
|
|
for (int i = 0; i < RTP_LOOP_PACKETS; i++) { |
|
|
|
if (phc->stream->lp_buf[i].len != phc->s.len) |
|
|
|
if (phc->mp.stream->lp_buf[i].len != phc->s.len) |
|
|
|
continue; |
|
|
|
if (memcmp(phc->stream->lp_buf[i].buf, phc->s.s, MIN(phc->s.len, RTP_LOOP_PROTECT))) |
|
|
|
if (memcmp(phc->mp.stream->lp_buf[i].buf, phc->s.s, MIN(phc->s.len, RTP_LOOP_PROTECT))) |
|
|
|
continue; |
|
|
|
|
|
|
|
__C_DBG("packet dupe"); |
|
|
|
if (phc->stream->lp_count >= RTP_LOOP_MAX_COUNT) { |
|
|
|
if (phc->mp.stream->lp_count >= RTP_LOOP_MAX_COUNT) { |
|
|
|
ilog(LOG_WARNING, "More than %d duplicate packets detected, dropping packet " |
|
|
|
"to avoid potential loop", RTP_LOOP_MAX_COUNT); |
|
|
|
mutex_unlock(&phc->stream->in_lock); |
|
|
|
mutex_unlock(&phc->mp.stream->in_lock); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
phc->stream->lp_count++; |
|
|
|
phc->mp.stream->lp_count++; |
|
|
|
goto loop_ok; |
|
|
|
} |
|
|
|
|
|
|
|
/* not a dupe */ |
|
|
|
phc->stream->lp_count = 0; |
|
|
|
phc->stream->lp_buf[phc->stream->lp_idx].len = phc->s.len; |
|
|
|
memcpy(phc->stream->lp_buf[phc->stream->lp_idx].buf, phc->s.s, MIN(phc->s.len, RTP_LOOP_PROTECT)); |
|
|
|
phc->stream->lp_idx = (phc->stream->lp_idx + 1) % RTP_LOOP_PACKETS; |
|
|
|
phc->mp.stream->lp_count = 0; |
|
|
|
phc->mp.stream->lp_buf[phc->mp.stream->lp_idx].len = phc->s.len; |
|
|
|
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->stream->in_lock); |
|
|
|
mutex_unlock(&phc->mp.stream->in_lock); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -1235,18 +1236,18 @@ loop_ok: |
|
|
|
// sink is set to where to forward the packet to |
|
|
|
static void media_packet_rtcp_demux(struct packet_handler_ctx *phc) |
|
|
|
{ |
|
|
|
phc->in_srtp = phc->stream; |
|
|
|
phc->sink = phc->stream->rtp_sink; |
|
|
|
if (!phc->sink && PS_ISSET(phc->stream, RTCP)) { |
|
|
|
phc->sink = phc->stream->rtcp_sink; |
|
|
|
phc->in_srtp = phc->mp.stream; |
|
|
|
phc->sink = phc->mp.stream->rtp_sink; |
|
|
|
if (!phc->sink && PS_ISSET(phc->mp.stream, RTCP)) { |
|
|
|
phc->sink = phc->mp.stream->rtcp_sink; |
|
|
|
phc->rtcp = 1; |
|
|
|
} |
|
|
|
else if (phc->stream->rtcp_sink) { |
|
|
|
int muxed_rtcp = rtcp_demux(&phc->s, phc->media); |
|
|
|
else if (phc->mp.stream->rtcp_sink) { |
|
|
|
int muxed_rtcp = rtcp_demux(&phc->s, phc->mp.media); |
|
|
|
if (muxed_rtcp == 2) { |
|
|
|
phc->sink = phc->stream->rtcp_sink; |
|
|
|
phc->sink = phc->mp.stream->rtcp_sink; |
|
|
|
phc->rtcp = 1; |
|
|
|
phc->in_srtp = phc->stream->rtcp_sibling; // use RTCP SRTP context |
|
|
|
phc->in_srtp = phc->mp.stream->rtcp_sibling; // use RTCP SRTP context |
|
|
|
} |
|
|
|
} |
|
|
|
phc->out_srtp = phc->sink; |
|
|
|
@ -1259,9 +1260,9 @@ static void media_packet_rtp(struct packet_handler_ctx *phc) |
|
|
|
{ |
|
|
|
phc->payload_type = -1; |
|
|
|
|
|
|
|
if (G_UNLIKELY(!phc->media->protocol)) |
|
|
|
if (G_UNLIKELY(!phc->mp.media->protocol)) |
|
|
|
return; |
|
|
|
if (G_UNLIKELY(!phc->media->protocol->rtp)) |
|
|
|
if (G_UNLIKELY(!phc->mp.media->protocol->rtp)) |
|
|
|
return; |
|
|
|
|
|
|
|
if (G_LIKELY(!phc->rtcp && !rtp_payload(&phc->mp.rtp, &phc->mp.payload, &phc->s))) { |
|
|
|
@ -1269,7 +1270,7 @@ static void media_packet_rtp(struct packet_handler_ctx *phc) |
|
|
|
|
|
|
|
if (G_LIKELY(phc->out_srtp != NULL)) |
|
|
|
__stream_ssrc(phc->in_srtp, phc->out_srtp, phc->mp.rtp->ssrc, &phc->mp.ssrc_in, |
|
|
|
&phc->mp.ssrc_out, phc->call->ssrc_hash); |
|
|
|
&phc->mp.ssrc_out, phc->mp.call->ssrc_hash); |
|
|
|
|
|
|
|
// check the payload type |
|
|
|
// XXX redundant between SSRC handling and codec_handler stuff -> combine |
|
|
|
@ -1279,11 +1280,11 @@ static void media_packet_rtp(struct packet_handler_ctx *phc) |
|
|
|
|
|
|
|
// XXX convert to array? or keep last pointer? |
|
|
|
// XXX yet another hash table per payload type -> combine |
|
|
|
struct rtp_stats *rtp_s = g_hash_table_lookup(phc->stream->rtp_stats, &phc->payload_type); |
|
|
|
struct rtp_stats *rtp_s = g_hash_table_lookup(phc->mp.stream->rtp_stats, &phc->payload_type); |
|
|
|
if (!rtp_s) { |
|
|
|
ilog(LOG_WARNING | LOG_FLAG_LIMIT, |
|
|
|
"RTP packet with unknown payload type %u received", phc->payload_type); |
|
|
|
atomic64_inc(&phc->stream->stats.errors); |
|
|
|
atomic64_inc(&phc->mp.stream->stats.errors); |
|
|
|
atomic64_inc(&rtpe_statsps.errors); |
|
|
|
} |
|
|
|
|
|
|
|
@ -1295,7 +1296,7 @@ static void media_packet_rtp(struct packet_handler_ctx *phc) |
|
|
|
else if (phc->rtcp && !rtcp_payload(&phc->mp.rtcp, NULL, &phc->s)) { |
|
|
|
if (G_LIKELY(phc->out_srtp != NULL)) |
|
|
|
__stream_ssrc(phc->in_srtp, phc->out_srtp, phc->mp.rtcp->ssrc, &phc->mp.ssrc_in, |
|
|
|
&phc->mp.ssrc_out, phc->call->ssrc_hash); |
|
|
|
&phc->mp.ssrc_out, phc->mp.call->ssrc_hash); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1320,7 +1321,7 @@ static int media_packet_decrypt(struct packet_handler_ctx *phc) |
|
|
|
* 1 = forward and push update to redis */ |
|
|
|
int ret = 0; |
|
|
|
if (phc->decrypt_func) |
|
|
|
ret = phc->decrypt_func(&phc->s, phc->in_srtp, phc->sfd, &phc->fsin, &phc->tv, phc->mp.ssrc_in); |
|
|
|
ret = phc->decrypt_func(&phc->s, phc->in_srtp, phc->mp.sfd, &phc->mp.fsin, &phc->mp.tv, phc->mp.ssrc_in); |
|
|
|
|
|
|
|
mutex_unlock(&phc->in_srtp->in_lock); |
|
|
|
|
|
|
|
@ -1361,50 +1362,50 @@ static int media_packet_address_check(struct packet_handler_ctx *phc) |
|
|
|
struct endpoint endpoint; |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
mutex_lock(&phc->stream->in_lock); |
|
|
|
mutex_lock(&phc->mp.stream->in_lock); |
|
|
|
|
|
|
|
/* we're OK to (potentially) use the source address of this packet as destination |
|
|
|
* in the other direction. */ |
|
|
|
/* if the other side hasn't been signalled yet, just forward the packet */ |
|
|
|
if (!PS_ISSET(phc->stream, FILLED)) { |
|
|
|
__C_DBG("stream %s:%d not FILLED", sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
if (!PS_ISSET(phc->mp.stream, FILLED)) { |
|
|
|
__C_DBG("stream %s:%d not FILLED", sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
goto out; |
|
|
|
} |
|
|
|
|
|
|
|
/* do not pay attention to source addresses of incoming packets for asymmetric streams */ |
|
|
|
if (MEDIA_ISSET(phc->media, ASYMMETRIC)) |
|
|
|
PS_SET(phc->stream, CONFIRMED); |
|
|
|
if (MEDIA_ISSET(phc->mp.media, ASYMMETRIC)) |
|
|
|
PS_SET(phc->mp.stream, CONFIRMED); |
|
|
|
|
|
|
|
/* confirm sink for unidirectional streams in order to kernelize */ |
|
|
|
if (MEDIA_ISSET(phc->media, UNIDIRECTIONAL)) |
|
|
|
if (MEDIA_ISSET(phc->mp.media, UNIDIRECTIONAL)) |
|
|
|
PS_SET(phc->sink, CONFIRMED); |
|
|
|
|
|
|
|
/* if we have already updated the endpoint in the past ... */ |
|
|
|
if (PS_ISSET(phc->stream, CONFIRMED)) { |
|
|
|
if (PS_ISSET(phc->mp.stream, CONFIRMED)) { |
|
|
|
/* see if we need to compare the source address with the known endpoint */ |
|
|
|
if (PS_ISSET2(phc->stream, STRICT_SOURCE, MEDIA_HANDOVER)) { |
|
|
|
endpoint = phc->fsin; |
|
|
|
mutex_lock(&phc->stream->out_lock); |
|
|
|
if (PS_ISSET2(phc->mp.stream, STRICT_SOURCE, MEDIA_HANDOVER)) { |
|
|
|
endpoint = phc->mp.fsin; |
|
|
|
mutex_lock(&phc->mp.stream->out_lock); |
|
|
|
|
|
|
|
int tmp = memcmp(&endpoint, &phc->stream->endpoint, sizeof(endpoint)); |
|
|
|
if (tmp && PS_ISSET(phc->stream, MEDIA_HANDOVER)) { |
|
|
|
int tmp = memcmp(&endpoint, &phc->mp.stream->endpoint, sizeof(endpoint)); |
|
|
|
if (tmp && PS_ISSET(phc->mp.stream, MEDIA_HANDOVER)) { |
|
|
|
/* out_lock remains locked */ |
|
|
|
ilog(LOG_INFO, "Peer address changed to %s", endpoint_print_buf(&phc->fsin)); |
|
|
|
ilog(LOG_INFO, "Peer address changed to %s", endpoint_print_buf(&phc->mp.fsin)); |
|
|
|
phc->unkernelize = 1; |
|
|
|
phc->update = 1; |
|
|
|
phc->stream->endpoint = phc->fsin; |
|
|
|
phc->mp.stream->endpoint = phc->mp.fsin; |
|
|
|
goto update_addr; |
|
|
|
} |
|
|
|
|
|
|
|
mutex_unlock(&phc->stream->out_lock); |
|
|
|
mutex_unlock(&phc->mp.stream->out_lock); |
|
|
|
|
|
|
|
if (tmp && PS_ISSET(phc->stream, STRICT_SOURCE)) { |
|
|
|
if (tmp && PS_ISSET(phc->mp.stream, STRICT_SOURCE)) { |
|
|
|
ilog(LOG_INFO, "Drop due to strict-source attribute; got %s:%d, expected %s:%d", |
|
|
|
sockaddr_print_buf(&endpoint.address), endpoint.port, |
|
|
|
sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
atomic64_inc(&phc->stream->stats.errors); |
|
|
|
sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
atomic64_inc(&phc->mp.stream->stats.errors); |
|
|
|
ret = -1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
@ -1415,72 +1416,72 @@ static int media_packet_address_check(struct packet_handler_ctx *phc) |
|
|
|
|
|
|
|
/* wait at least 3 seconds after last signal before committing to a particular |
|
|
|
* endpoint address */ |
|
|
|
if (!phc->call->last_signal || rtpe_now.tv_sec <= phc->call->last_signal + 3) |
|
|
|
if (!phc->mp.call->last_signal || rtpe_now.tv_sec <= phc->mp.call->last_signal + 3) |
|
|
|
goto update_peerinfo; |
|
|
|
|
|
|
|
phc->kernelize = 1; |
|
|
|
phc->update = 1; |
|
|
|
|
|
|
|
ilog(LOG_INFO, "Confirmed peer address as %s", endpoint_print_buf(&phc->fsin)); |
|
|
|
ilog(LOG_INFO, "Confirmed peer address as %s", endpoint_print_buf(&phc->mp.fsin)); |
|
|
|
|
|
|
|
PS_SET(phc->stream, CONFIRMED); |
|
|
|
PS_SET(phc->mp.stream, CONFIRMED); |
|
|
|
|
|
|
|
update_peerinfo: |
|
|
|
mutex_lock(&phc->stream->out_lock); |
|
|
|
endpoint = phc->stream->endpoint; |
|
|
|
phc->stream->endpoint = phc->fsin; |
|
|
|
if (memcmp(&endpoint, &phc->stream->endpoint, sizeof(endpoint))) |
|
|
|
mutex_lock(&phc->mp.stream->out_lock); |
|
|
|
endpoint = phc->mp.stream->endpoint; |
|
|
|
phc->mp.stream->endpoint = phc->mp.fsin; |
|
|
|
if (memcmp(&endpoint, &phc->mp.stream->endpoint, sizeof(endpoint))) |
|
|
|
phc->update = 1; |
|
|
|
update_addr: |
|
|
|
mutex_unlock(&phc->stream->out_lock); |
|
|
|
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->stream->selected_sfd && phc->sfd != phc->stream->selected_sfd) { |
|
|
|
ilog(LOG_INFO, "Switching local interface to %s", endpoint_print_buf(&phc->sfd->socket.local)); |
|
|
|
phc->stream->selected_sfd = phc->sfd; |
|
|
|
if (phc->mp.stream->selected_sfd && phc->mp.sfd != phc->mp.stream->selected_sfd) { |
|
|
|
ilog(LOG_INFO, "Switching local interface to %s", endpoint_print_buf(&phc->mp.sfd->socket.local)); |
|
|
|
phc->mp.stream->selected_sfd = phc->mp.sfd; |
|
|
|
phc->update = 1; |
|
|
|
} |
|
|
|
|
|
|
|
out: |
|
|
|
mutex_unlock(&phc->stream->in_lock); |
|
|
|
mutex_unlock(&phc->mp.stream->in_lock); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void media_packet_kernel_check(struct packet_handler_ctx *phc) { |
|
|
|
if (PS_ISSET(phc->stream, NO_KERNEL_SUPPORT)) { |
|
|
|
__C_DBG("stream %s:%d NO_KERNEL_SUPPORT", sockaddr_print_buf(&phc->stream->endpoint.address), phc->stream->endpoint.port); |
|
|
|
if (PS_ISSET(phc->mp.stream, NO_KERNEL_SUPPORT)) { |
|
|
|
__C_DBG("stream %s:%d NO_KERNEL_SUPPORT", sockaddr_print_buf(&phc->mp.stream->endpoint.address), phc->mp.stream->endpoint.port); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!PS_ISSET(phc->stream, CONFIRMED)) { |
|
|
|
__C_DBG("stream %s:%d not CONFIRMED", sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
if (!PS_ISSET(phc->mp.stream, CONFIRMED)) { |
|
|
|
__C_DBG("stream %s:%d not CONFIRMED", sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!phc->sink) { |
|
|
|
__C_DBG("sink is NULL for stream %s:%d", sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
__C_DBG("sink is NULL for stream %s:%d", sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!PS_ISSET(phc->sink, CONFIRMED)) { |
|
|
|
__C_DBG("sink not CONFIRMED for stream %s:%d", |
|
|
|
sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!PS_ISSET(phc->sink, FILLED)) { |
|
|
|
__C_DBG("sink not FILLED for stream %s:%d", sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
__C_DBG("sink not FILLED for stream %s:%d", sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
kernelize(phc->stream); |
|
|
|
kernelize(phc->mp.stream); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1490,13 +1491,14 @@ static int do_rtcp(struct packet_handler_ctx *phc) { |
|
|
|
// XXX rewrite/consume for transcoding |
|
|
|
|
|
|
|
GQueue rtcp_list = G_QUEUE_INIT; |
|
|
|
if (rtcp_parse(&rtcp_list, &phc->s, phc->sfd, &phc->fsin, &phc->tv)) |
|
|
|
if (rtcp_parse(&rtcp_list, &phc->mp)) |
|
|
|
goto out; |
|
|
|
if (phc->rtcp_filter) |
|
|
|
if (phc->rtcp_filter(&phc->s, &rtcp_list)) |
|
|
|
if (phc->rtcp_filter(&phc->mp, &rtcp_list)) |
|
|
|
goto out; |
|
|
|
|
|
|
|
codec_add_raw_packet(&phc->mp, &phc->s); |
|
|
|
// queue for output |
|
|
|
codec_add_raw_packet(&phc->mp); |
|
|
|
ret = 0; |
|
|
|
|
|
|
|
out: |
|
|
|
@ -1529,20 +1531,20 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
* always holds true */ |
|
|
|
int ret = 0, handler_ret = 0; |
|
|
|
|
|
|
|
phc->call = phc->sfd->call; |
|
|
|
phc->mp.call = phc->mp.sfd->call; |
|
|
|
|
|
|
|
rwlock_lock_r(&phc->call->master_lock); |
|
|
|
rwlock_lock_r(&phc->mp.call->master_lock); |
|
|
|
|
|
|
|
phc->stream = phc->sfd->stream; |
|
|
|
if (G_UNLIKELY(!phc->stream)) |
|
|
|
phc->mp.stream = phc->mp.sfd->stream; |
|
|
|
if (G_UNLIKELY(!phc->mp.stream)) |
|
|
|
goto out; |
|
|
|
__C_DBG("Handling packet on: %s:%d", sockaddr_print_buf(&phc->stream->endpoint.address), |
|
|
|
phc->stream->endpoint.port); |
|
|
|
__C_DBG("Handling packet on: %s:%d", sockaddr_print_buf(&phc->mp.stream->endpoint.address), |
|
|
|
phc->mp.stream->endpoint.port); |
|
|
|
|
|
|
|
|
|
|
|
phc->media = phc->stream->media; |
|
|
|
phc->mp.media = phc->mp.stream->media; |
|
|
|
|
|
|
|
if (!phc->stream->selected_sfd) |
|
|
|
if (!phc->mp.stream->selected_sfd) |
|
|
|
goto out; |
|
|
|
|
|
|
|
|
|
|
|
@ -1556,7 +1558,7 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
|
|
|
|
|
|
|
|
#if RTP_LOOP_PROTECT |
|
|
|
if (MEDIA_ISSET(phc->media, LOOP_CHECK)) { |
|
|
|
if (MEDIA_ISSET(phc->mp.media, LOOP_CHECK)) { |
|
|
|
if (media_loop_detect(phc)) |
|
|
|
goto out; |
|
|
|
} |
|
|
|
@ -1575,8 +1577,8 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
if (G_UNLIKELY(!phc->sink || !phc->sink->selected_sfd || !phc->out_srtp |
|
|
|
|| !phc->out_srtp->selected_sfd || !phc->in_srtp->selected_sfd)) |
|
|
|
{ |
|
|
|
ilog(LOG_WARNING, "RTP packet from %s discarded", endpoint_print_buf(&phc->fsin)); |
|
|
|
atomic64_inc(&phc->stream->stats.errors); |
|
|
|
ilog(LOG_WARNING, "RTP packet from %s discarded", endpoint_print_buf(&phc->mp.fsin)); |
|
|
|
atomic64_inc(&phc->mp.stream->stats.errors); |
|
|
|
atomic64_inc(&rtpe_statsps.errors); |
|
|
|
goto out; |
|
|
|
} |
|
|
|
@ -1585,19 +1587,21 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
handler_ret = media_packet_decrypt(phc); |
|
|
|
|
|
|
|
// If recording pcap dumper is set, then we record the call. |
|
|
|
if (phc->call->recording) |
|
|
|
dump_packet(phc->call->recording, phc->stream, &phc->s); |
|
|
|
if (phc->mp.call->recording) |
|
|
|
dump_packet(phc->mp.call->recording, phc->mp.stream, &phc->s); |
|
|
|
|
|
|
|
// ready to process |
|
|
|
|
|
|
|
phc->mp.raw = phc->s; |
|
|
|
|
|
|
|
// RTCP detection is further up, so we could make this determination there |
|
|
|
if (phc->mp.rtcp) { |
|
|
|
if (phc->rtcp) { |
|
|
|
if (do_rtcp(phc)) |
|
|
|
goto drop; |
|
|
|
} |
|
|
|
else { |
|
|
|
struct codec_handler *transcoder = codec_handler_get(phc->media, phc->payload_type); |
|
|
|
struct codec_handler *transcoder = codec_handler_get(phc->mp.media, phc->payload_type); |
|
|
|
// this transfers the packet from 's' to 'packets_out' |
|
|
|
phc->mp.raw = phc->s; |
|
|
|
if (transcoder->func(transcoder, phc->media, &phc->mp)) |
|
|
|
if (transcoder->func(transcoder, phc->mp.media, &phc->mp)) |
|
|
|
goto drop; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1605,7 +1609,7 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
handler_ret = media_packet_encrypt(phc); |
|
|
|
|
|
|
|
if (phc->update) // for RTCP packet index updates |
|
|
|
unkernelize(phc->stream); |
|
|
|
unkernelize(phc->mp.stream); |
|
|
|
|
|
|
|
|
|
|
|
int address_check = media_packet_address_check(phc); |
|
|
|
@ -1646,7 +1650,7 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
if (ret == -1) { |
|
|
|
ret = -errno; |
|
|
|
ilog(LOG_DEBUG,"Error when sending message. Error: %s",strerror(errno)); |
|
|
|
atomic64_inc(&phc->stream->stats.errors); |
|
|
|
atomic64_inc(&phc->mp.stream->stats.errors); |
|
|
|
atomic64_inc(&rtpe_statsps.errors); |
|
|
|
goto out; |
|
|
|
} |
|
|
|
@ -1654,20 +1658,20 @@ static int stream_packet(struct packet_handler_ctx *phc) { |
|
|
|
drop: |
|
|
|
ret = 0; |
|
|
|
// XXX separate stats for received/sent |
|
|
|
atomic64_inc(&phc->stream->stats.packets); |
|
|
|
atomic64_add(&phc->stream->stats.bytes, phc->s.len); |
|
|
|
atomic64_set(&phc->stream->last_packet, rtpe_now.tv_sec); |
|
|
|
atomic64_inc(&phc->mp.stream->stats.packets); |
|
|
|
atomic64_add(&phc->mp.stream->stats.bytes, phc->s.len); |
|
|
|
atomic64_set(&phc->mp.stream->last_packet, rtpe_now.tv_sec); |
|
|
|
atomic64_inc(&rtpe_statsps.packets); |
|
|
|
atomic64_add(&rtpe_statsps.bytes, phc->s.len); |
|
|
|
|
|
|
|
out: |
|
|
|
if (phc->unkernelize) { |
|
|
|
stream_unconfirm(phc->stream); |
|
|
|
stream_unconfirm(phc->stream->rtp_sink); |
|
|
|
stream_unconfirm(phc->stream->rtcp_sink); |
|
|
|
stream_unconfirm(phc->mp.stream); |
|
|
|
stream_unconfirm(phc->mp.stream->rtp_sink); |
|
|
|
stream_unconfirm(phc->mp.stream->rtcp_sink); |
|
|
|
} |
|
|
|
|
|
|
|
rwlock_unlock_r(&phc->call->master_lock); |
|
|
|
rwlock_unlock_r(&phc->mp.call->master_lock); |
|
|
|
|
|
|
|
g_queue_clear_full(&phc->mp.packets_out, codec_packet_free); |
|
|
|
|
|
|
|
@ -1698,10 +1702,10 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) { |
|
|
|
|
|
|
|
struct packet_handler_ctx phc; |
|
|
|
ZERO(phc); |
|
|
|
phc.sfd = sfd; |
|
|
|
phc.mp.sfd = sfd; |
|
|
|
|
|
|
|
ret = socket_recvfrom_ts(&sfd->socket, buf + RTP_BUFFER_HEAD_ROOM, MAX_RTP_PACKET_SIZE, |
|
|
|
&phc.fsin, &phc.tv); |
|
|
|
&phc.mp.fsin, &phc.mp.tv); |
|
|
|
|
|
|
|
if (ret < 0) { |
|
|
|
if (errno == EINTR) |
|
|
|
|