TT#12800 add ssrc handling into packet_stream struct

Change-Id: I7da97a6435854a846d2782448b32c69327756ccf
changes/52/12652/12
Richard Fuchs 8 years ago
parent 0b63050c46
commit 868c3b64fe

@ -546,22 +546,22 @@ static void callmaster_timer(void *ptr) {
/* XXX this only works if the kernel module actually gets to see the packets. */
if (sink) {
mutex_lock(&sink->out_lock);
if (sink->crypto.params.crypto_suite
&& ke->target.ssrc == sink->crypto.ssrc
&& ke->target.encrypt.last_index - sink->crypto.last_index > 0x4000)
if (sink->crypto.params.crypto_suite && sink->ssrc_out
&& ke->target.ssrc == sink->ssrc_out->parent->ssrc
&& ke->target.encrypt.last_index - sink->ssrc_out->srtp_index > 0x4000)
{
sink->crypto.last_index = ke->target.encrypt.last_index;
sink->ssrc_out->srtp_index = ke->target.encrypt.last_index;
update = 1;
}
mutex_unlock(&sink->out_lock);
}
mutex_lock(&ps->in_lock);
if (sfd->crypto.params.crypto_suite
&& ke->target.ssrc == sfd->crypto.ssrc
&& ke->target.decrypt.last_index - sfd->crypto.last_index > 0x4000)
if (sfd->crypto.params.crypto_suite && ps->ssrc_in
&& ke->target.ssrc == ps->ssrc_in->parent->ssrc
&& ke->target.decrypt.last_index - ps->ssrc_in->srtp_index > 0x4000)
{
sfd->crypto.last_index = ke->target.decrypt.last_index;
ps->ssrc_in->srtp_index = ke->target.decrypt.last_index;
update = 1;
}
mutex_unlock(&ps->in_lock);
@ -1884,11 +1884,13 @@ void call_destroy(struct call *c) {
char *addr = sockaddr_print_buf(&ps->endpoint.address);
char *local_addr = ps->selected_sfd ? sockaddr_print_buf(&ps->selected_sfd->socket.local.address) : "0.0.0.0";
ilog(LOG_INFO, "--------- Port %15s:%-5u <> %15s:%-5u%s, "
""UINT64F" p, "UINT64F" b, "UINT64F" e, "UINT64F" last_packet", local_addr,
ilog(LOG_INFO, "--------- Port %15s:%-5u <> %15s:%-5u%s, SSRC %" PRIu32 ", "
""UINT64F" p, "UINT64F" b, "UINT64F" e, "UINT64F" last_packet",
local_addr,
(unsigned int) (ps->selected_sfd ? ps->selected_sfd->socket.local.port : 0),
addr, ps->endpoint.port,
(!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "",
ps->ssrc_in ? ps->ssrc_in->parent->ssrc : 0,
atomic64_get(&ps->stats.packets),
atomic64_get(&ps->stats.bytes),
atomic64_get(&ps->stats.errors),

@ -282,6 +282,8 @@ struct packet_stream {
struct endpoint endpoint; /* LOCK: out_lock */
struct endpoint advertised_endpoint; /* RO */
struct crypto_context crypto; /* OUT direction, LOCK: out_lock */
struct ssrc_ctx *ssrc_in, /* LOCK: in_lock */
*ssrc_out; /* LOCK: out_lock */
struct stats stats;
struct stats kernel_stats;

@ -82,8 +82,6 @@ struct crypto_context {
char session_salt[SRTP_MAX_SESSION_SALT_LEN]; /* k_s */
char session_auth_key[SRTP_MAX_SESSION_AUTH_LEN];
u_int32_t ssrc;
u_int64_t last_index;
/* XXX replay list */
/* <from, to>? */
@ -145,9 +143,8 @@ INLINE void crypto_cleanup(struct crypto_context *c) {
c->params.crypto_suite = NULL;
}
INLINE void crypto_reset(struct crypto_context *c) {
// XXX reset details from ssrc_ctx?
crypto_cleanup(c);
c->last_index = 0;
c->ssrc = 0;
}
INLINE void crypto_params_copy(struct crypto_params *o, const struct crypto_params *i, int copy_sp) {
struct crypto_session_params sp;

@ -35,7 +35,7 @@
typedef int (*rewrite_func)(str *, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
struct streamhandler_io {
@ -56,20 +56,20 @@ static int __k_srtp_encrypt(struct rtpengine_srtp *s, struct packet_stream *);
static int __k_srtp_decrypt(struct rtpengine_srtp *s, struct packet_stream *);
static int call_noop_rtcp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
static int call_avp2savp_rtp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
static int call_savp2avp_rtp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
static int call_avp2savp_rtcp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
static int call_savp2avp_rtcp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
static int call_avpf2avp_rtcp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
//static int call_avpf2savp_rtcp(str *s, struct packet_stream *);
static int call_savpf2avp_rtcp(str *s, struct packet_stream *, struct stream_fd *, const endpoint_t *,
const struct timeval *);
const struct timeval *, struct ssrc_ctx *);
//static int call_savpf2savp_rtcp(str *s, struct packet_stream *);
@ -805,45 +805,45 @@ static int rtcp_demux(str *s, struct call_media *media) {
}
static int call_noop_rtcp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
rtcp_parse(s, sfd, src, tv);
return 0;
}
static int call_avpf2avp_rtcp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
return rtcp_avpf2avp(s, sfd, src, tv); // also does rtcp_parse
}
static int call_avp2savp_rtp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
return rtp_avp2savp(s, &stream->crypto, stream->call->ssrc_hash, SSRC_DIR_OUTPUT);
return rtp_avp2savp(s, &stream->crypto, ssrc_ctx);
}
static int call_avp2savp_rtcp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
return rtcp_avp2savp(s, &stream->crypto);
return rtcp_avp2savp(s, &stream->crypto, ssrc_ctx);
}
static int call_savp2avp_rtp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
return rtp_savp2avp(s, &stream->selected_sfd->crypto, stream->call->ssrc_hash, SSRC_DIR_INPUT);
return rtp_savp2avp(s, &stream->selected_sfd->crypto, ssrc_ctx);
}
static int call_savp2avp_rtcp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
int ret = rtcp_savp2avp(s, &stream->selected_sfd->crypto);
int ret = rtcp_savp2avp(s, &stream->selected_sfd->crypto, ssrc_ctx);
if (ret < 0)
return ret;
rtcp_parse(s, sfd, src, tv);
return ret;
}
static int call_savpf2avp_rtcp(str *s, struct packet_stream *stream, struct stream_fd *sfd, const endpoint_t *src,
const struct timeval *tv)
const struct timeval *tv, struct ssrc_ctx *ssrc_ctx)
{
int ret;
ret = rtcp_savp2avp(s, &stream->selected_sfd->crypto);
ret = rtcp_savp2avp(s, &stream->selected_sfd->crypto, ssrc_ctx);
if (ret < 0)
return ret;
return rtcp_avpf2avp(s, sfd, src, tv);
@ -854,7 +854,7 @@ static int __k_null(struct rtpengine_srtp *s, struct packet_stream *stream) {
*s = __res_null;
return 0;
}
static int __k_srtp_crypt(struct rtpengine_srtp *s, struct crypto_context *c) {
static int __k_srtp_crypt(struct rtpengine_srtp *s, struct crypto_context *c, struct ssrc_ctx *ssrc_ctx) {
if (!c->params.crypto_suite)
return -1;
@ -862,7 +862,7 @@ static int __k_srtp_crypt(struct rtpengine_srtp *s, struct crypto_context *c) {
.cipher = c->params.crypto_suite->kernel_cipher,
.hmac = c->params.crypto_suite->kernel_hmac,
.mki_len = c->params.mki_len,
.last_index = c->last_index,
.last_index = ssrc_ctx->srtp_index,
.auth_tag_len = c->params.crypto_suite->srtp_auth_tag,
};
if (c->params.mki_len)
@ -880,10 +880,10 @@ static int __k_srtp_crypt(struct rtpengine_srtp *s, struct crypto_context *c) {
return 0;
}
static int __k_srtp_encrypt(struct rtpengine_srtp *s, struct packet_stream *stream) {
return __k_srtp_crypt(s, &stream->crypto);
return __k_srtp_crypt(s, &stream->crypto, stream->ssrc_out);
}
static int __k_srtp_decrypt(struct rtpengine_srtp *s, struct packet_stream *stream) {
return __k_srtp_crypt(s, &stream->selected_sfd->crypto);
return __k_srtp_crypt(s, &stream->selected_sfd->crypto, stream->ssrc_in);
}
INLINE void __re_address_translate_ep(struct re_address *o, const endpoint_t *ep) {
@ -962,7 +962,7 @@ void kernelize(struct packet_stream *stream) {
__re_address_translate_ep(&reti.dst_addr, &sink->endpoint);
__re_address_translate_ep(&reti.src_addr, &sink->selected_sfd->socket.local);
reti.ssrc = sink->crypto.ssrc;
reti.ssrc = sink->ssrc_in ? sink->ssrc_in->parent->ssrc : 0;
stream->handler->in->kernel(&reti.decrypt, stream);
stream->handler->out->kernel(&reti.encrypt, sink);
@ -1095,6 +1095,38 @@ noop:
}
// check and update SSRC pointers
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);
// 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->ssrc != ssrc)) {
// SSRC mismatch - get the new entry
(*ssrc_in_p) = in_srtp->ssrc_in =
get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_INPUT);
}
mutex_unlock(&in_srtp->in_lock);
// out direction
mutex_lock(&out_srtp->out_lock);
(*ssrc_out_p) = out_srtp->ssrc_out;
if (G_UNLIKELY(!(*ssrc_out_p) || (*ssrc_out_p)->parent->ssrc != ssrc)) {
// SSRC mismatch - get the new entry
(*ssrc_out_p) = out_srtp->ssrc_out =
get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_OUTPUT);
}
mutex_unlock(&out_srtp->out_lock);
}
/* XXX split this function into pieces */
/* called lock-free */
static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin, const struct timeval *tv) {
@ -1132,7 +1164,9 @@ static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin,
rewrite_func rwf_in, rwf_out;
//struct local_intf *loc_addr;
struct rtp_header *rtp_h;
struct rtcp_packet *rtcp_h;
struct rtp_stats *rtp_s;
struct ssrc_ctx *ssrc_in = NULL, *ssrc_out = NULL;
call = sfd->call;
cm = call->callmaster;
@ -1227,33 +1261,39 @@ loop_ok:
out_srtp = sink->rtcp_sibling;
/* stats per RTP payload type */
/* RTP/RTCP specifics */
if (media->protocol && media->protocol->rtp && !rtcp && !rtp_payload(&rtp_h, NULL, s)) {
i = (rtp_h->m_pt & 0x7f);
if (G_LIKELY(media->protocol && media->protocol->rtp)) {
if (G_LIKELY(!rtcp && !rtp_payload(&rtp_h, NULL, s))) {
__stream_ssrc(in_srtp, out_srtp, rtp_h->ssrc, &ssrc_in, &ssrc_out, call->ssrc_hash);
// XXX two hash table lookups for each packet, not ideal
// XXX limit size of hash tables
rtp_s = g_hash_table_lookup(stream->rtp_stats, &i);
if (!rtp_s) {
ilog(LOG_WARNING | LOG_FLAG_LIMIT,
"RTP packet with unknown payload type %u received", i);
atomic64_inc(&stream->stats.errors);
atomic64_inc(&cm->statsps.errors);
}
// check the payload type
i = (rtp_h->m_pt & 0x7f);
ssrc_in->parent->payload_type = i;
else {
atomic64_inc(&rtp_s->packets);
atomic64_add(&rtp_s->bytes, s->len);
// XXX limit size of hash tables
// XXX convert to array? or keep last pointer?
rtp_s = g_hash_table_lookup(stream->rtp_stats, &i);
if (!rtp_s) {
ilog(LOG_WARNING | LOG_FLAG_LIMIT,
"RTP packet with unknown payload type %u received", i);
atomic64_inc(&stream->stats.errors);
atomic64_inc(&cm->statsps.errors);
}
struct ssrc_entry *se = get_ssrc(ntohl(rtp_h->ssrc), call->ssrc_hash);
se->payload_type = i;
else {
atomic64_inc(&rtp_s->packets);
atomic64_add(&rtp_s->bytes, s->len);
}
}
else if (rtcp && !rtcp_payload(&rtcp_h, NULL, s)) {
__stream_ssrc(in_srtp, out_srtp, rtcp_h->ssrc, &ssrc_in, &ssrc_out, call->ssrc_hash);
}
}
/* do we have somewhere to forward it to? */
if (!sink || !sink->selected_sfd || !out_srtp->selected_sfd || !in_srtp->selected_sfd) {
if (G_UNLIKELY(!sink || !sink->selected_sfd || !out_srtp->selected_sfd || !in_srtp->selected_sfd)) {
ilog(LOG_WARNING, "RTP packet from %s discarded", endpoint_print_buf(fsin));
atomic64_inc(&stream->stats.errors);
atomic64_inc(&cm->statsps.errors);
@ -1267,7 +1307,7 @@ loop_ok:
determine_handler(in_srtp, sink);
if (!rtcp) {
if (G_LIKELY(!rtcp)) {
rwf_in = in_srtp->handler->in->rtp;
rwf_out = in_srtp->handler->out->rtp;
}
@ -1281,7 +1321,7 @@ loop_ok:
/* return values are: 0 = forward packet, -1 = error/dont forward,
* 1 = forward and push update to redis */
if (rwf_in) {
handler_ret = rwf_in(s, in_srtp, sfd, fsin, tv);
handler_ret = rwf_in(s, in_srtp, sfd, fsin, tv, ssrc_in);
}
// If recording pcap dumper is set, then we record the call.
@ -1289,9 +1329,9 @@ loop_ok:
dump_packet(call->recording, stream, s);
}
if (handler_ret >= 0) {
if (G_LIKELY(handler_ret >= 0)) {
if (rwf_out)
handler_ret += rwf_out(s, out_srtp, NULL, NULL, NULL);
handler_ret += rwf_out(s, out_srtp, NULL, NULL, NULL, ssrc_out);
}
if (handler_ret > 0) {

@ -29,6 +29,7 @@
#include "recording.h"
#include "rtplib.h"
#include "str.h"
#include "ssrc.h"
INLINE redisReply *redis_expect(int type, redisReply *r) {
@ -801,7 +802,7 @@ define_get_int_type(time_t, time_t, strtoull);
define_get_int_type(int, int, strtol);
define_get_int_type(unsigned, unsigned int, strtol);
//define_get_int_type(u16, u_int16_t, strtol);
define_get_int_type(u64, u_int64_t, strtoull);
//define_get_int_type(u64, u_int64_t, strtoull);
define_get_int_type(a64, atomic64, strtoa64);
define_get_type_format(str, str);
@ -998,22 +999,6 @@ err:
rlog(LOG_ERR, "Crypto params error: %s", err);
return -1;
}
static int redis_hash_get_crypto_context(struct crypto_context *out, const struct redis_hash *h) {
int ret;
ret = redis_hash_get_crypto_params(&out->params, h, "");
if (ret == 1)
return 0;
else if (ret)
return -1;
if (redis_hash_get_u64(&out->last_index, h, "last_index"))
return -1;
// coverity[check_return : FALSE]
redis_hash_get_unsigned(&out->ssrc, h, "ssrc");
return 0;
}
static int redis_sfds(struct call *c, struct redis_list *sfds) {
unsigned int i;
@ -1067,9 +1052,6 @@ static int redis_sfds(struct call *c, struct redis_list *sfds) {
goto err;
sfd = stream_fd_new(sock, c, loc);
// XXX tos
err = "failed to config crypto context";
if (redis_hash_get_crypto_context(&sfd->crypto, rh))
goto err;
sfds->ptrs[i] = sfd;
}
@ -1103,8 +1085,6 @@ static int redis_streams(struct call *c, struct redis_list *streams) {
return -1;
if (redis_hash_get_stats(&ps->stats, rh, "stats"))
return -1;
if (redis_hash_get_crypto_context(&ps->crypto, rh))
return -1;
streams->ptrs[i] = ps;
@ -1499,6 +1479,8 @@ static void json_restore_call(struct redis *r, struct callmaster *m, const str *
if (json_link_maps(c, &maps, &sfds, root_reader))
goto err8;
// XXX restore SSRC table
// presence of this key determines whether we were recording at all
if (!redis_hash_get_str(&s, &call, "recording_meta_prefix")) {
recording_start(c, s.s);
@ -1678,20 +1660,6 @@ static int json_update_crypto_params(JsonBuilder *builder, const char *pref,
return 0;
}
static void json_update_crypto_context(JsonBuilder *builder, const char *pref,
unsigned int unique_id,
const struct crypto_context *c)
{
char tmp[2048];
if (json_update_crypto_params(builder, pref, unique_id, "", &c->params))
return;
JSON_SET_SIMPLE("last_index","%" PRIu64, c->last_index);
JSON_SET_SIMPLE("ssrc","%u",(unsigned) c->ssrc);
}
static void json_update_dtls_fingerprint(JsonBuilder *builder, const char *pref,
unsigned int unique_id,
const struct dtls_fingerprint *f)
@ -1766,8 +1734,6 @@ char* redis_encode_json(struct call *c) {
JSON_SET_SIMPLE("local_intf_uid","%u",sfd->local_intf->unique_id);
JSON_SET_SIMPLE("stream","%u",sfd->stream->unique_id);
json_update_crypto_context(builder, "sfd", sfd->unique_id, &sfd->crypto);
}
json_builder_end_object (builder);
@ -1799,8 +1765,6 @@ char* redis_encode_json(struct call *c) {
JSON_SET_SIMPLE("stats-bytes","%" PRIu64, atomic64_get(&ps->stats.bytes));
JSON_SET_SIMPLE("stats-errors","%" PRIu64, atomic64_get(&ps->stats.errors));
json_update_crypto_context(builder, "stream", ps->unique_id, &ps->crypto);
}
json_builder_end_object (builder);
@ -1951,7 +1915,6 @@ char* redis_encode_json(struct call *c) {
json_builder_end_array (builder);
g_list_free(k);
}
for (l = c->endpoint_maps.head; l; l = l->next) {
@ -1990,6 +1953,29 @@ char* redis_encode_json(struct call *c) {
}
json_builder_end_array (builder);
}
// SSRC table dump
k = g_hash_table_get_values(c->ssrc_hash->ht);
json_builder_set_member_name(builder, "ssrc_table");
json_builder_begin_array (builder);
for (m = k; m; m = m->next) {
struct ssrc_entry *se = m->data;
json_builder_begin_object (builder);
JSON_SET_SIMPLE("ssrc","%" PRIu32, se->ssrc);
// XXX use function for in/out
JSON_SET_SIMPLE("in_srtp_index","%" PRIu64, se->input_ctx.srtp_index);
JSON_SET_SIMPLE("in_srtcp_index","%" PRIu64, se->input_ctx.srtcp_index);
JSON_SET_SIMPLE("out_srtp_index","%" PRIu64, se->output_ctx.srtp_index);
JSON_SET_SIMPLE("out_srtcp_index","%" PRIu64, se->output_ctx.srtcp_index);
JSON_SET_SIMPLE("payload_type","%i", se->payload_type);
// XXX add rest of info
json_builder_end_object (builder);
}
json_builder_end_array (builder);
g_list_free(k);
}
json_builder_end_object (builder);

@ -768,7 +768,7 @@ error:
return -1;
}
static int rtcp_payload(struct rtcp_packet **out, str *p, const str *s) {
int rtcp_payload(struct rtcp_packet **out, str *p, const str *s) {
struct rtcp_packet *rtcp;
const char *err;
@ -786,10 +786,14 @@ static int rtcp_payload(struct rtcp_packet **out, str *p, const str *s) {
&& rtcp->header.pt != RTCP_PT_RR)
goto error;
if (!p)
goto done;
*p = *s;
str_shift(p, sizeof(*rtcp));
*out = rtcp;
done:
*out = rtcp;
return 0;
error:
ilog(LOG_WARNING | LOG_FLAG_LIMIT, "Error parsing RTCP header: %s", err);
@ -797,21 +801,25 @@ error:
}
/* rfc 3711 section 3.4 */
int rtcp_avp2savp(str *s, struct crypto_context *c) {
int rtcp_avp2savp(str *s, struct crypto_context *c, struct ssrc_ctx *ssrc_ctx) {
struct rtcp_packet *rtcp;
u_int32_t *idx;
str to_auth, payload;
if (G_UNLIKELY(!ssrc_ctx))
return -1;
if (rtcp_payload(&rtcp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
if (!c->params.session_params.unencrypted_srtcp && crypto_encrypt_rtcp(c, rtcp, &payload, c->last_index))
if (!c->params.session_params.unencrypted_srtcp && crypto_encrypt_rtcp(c, rtcp, &payload,
ssrc_ctx->srtcp_index))
return -1;
idx = (void *) s->s + s->len;
*idx = htonl((c->params.session_params.unencrypted_srtcp ? 0ULL : 0x80000000ULL) | c->last_index++);
*idx = htonl((c->params.session_params.unencrypted_srtcp ? 0ULL : 0x80000000ULL) |
ssrc_ctx->srtcp_index++);
s->len += sizeof(*idx);
to_auth = *s;
@ -826,13 +834,15 @@ int rtcp_avp2savp(str *s, struct crypto_context *c) {
/* rfc 3711 section 3.4 */
int rtcp_savp2avp(str *s, struct crypto_context *c) {
int rtcp_savp2avp(str *s, struct crypto_context *c, struct ssrc_ctx *ssrc_ctx) {
struct rtcp_packet *rtcp;
str payload, to_auth, to_decrypt, auth_tag;
u_int32_t idx, *idx_p;
char hmac[20];
const char *err;
if (G_UNLIKELY(!ssrc_ctx))
return -1;
if (rtcp_payload(&rtcp, &payload, s))
return -1;
if (check_session_keys(c))

@ -7,12 +7,16 @@
struct crypto_context;
struct rtcp_packet;
struct ssrc_ctx;
int rtcp_avpf2avp(str *, struct stream_fd *sfd, const endpoint_t *, const struct timeval *);
int rtcp_avp2savp(str *, struct crypto_context *);
int rtcp_savp2avp(str *, struct crypto_context *);
int rtcp_avp2savp(str *, struct crypto_context *, struct ssrc_ctx *);
int rtcp_savp2avp(str *, struct crypto_context *, struct ssrc_ctx *);
int rtcp_payload(struct rtcp_packet **out, str *p, const str *s);
//void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *, const endpoint_t *, const struct timeval *);
void rtcp_parse(const str *, struct stream_fd *sfd, const endpoint_t *, const struct timeval *);

@ -18,7 +18,7 @@ INLINE int check_session_keys(struct crypto_context *c) {
str s;
const char *err;
if (c->have_session_key)
if (G_LIKELY(c->have_session_key))
return 0;
err = "SRTP output wanted, but no crypto suite was negotiated";
if (!c->params.crypto_suite)
@ -45,17 +45,17 @@ error:
return -1;
}
static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp) {
static u_int64_t packet_index(struct ssrc_ctx *ssrc_ctx, struct rtp_header *rtp) {
u_int16_t seq;
seq = ntohs(rtp->seq_num);
/* rfc 3711 section 3.3.1 */
if (G_UNLIKELY(!c->last_index))
c->last_index = seq;
if (G_UNLIKELY(!ssrc_ctx->srtp_index))
ssrc_ctx->srtp_index = seq;
/* rfc 3711 appendix A, modified, and sections 3.3 and 3.3.1 */
u_int16_t s_l = (c->last_index & 0x00000000ffffULL);
u_int32_t roc = (c->last_index & 0xffffffff0000ULL) >> 16;
u_int16_t s_l = (ssrc_ctx->srtp_index & 0x00000000ffffULL);
u_int32_t roc = (ssrc_ctx->srtp_index & 0xffffffff0000ULL) >> 16;
u_int32_t v = 0;
if (s_l < 0x8000) {
@ -70,8 +70,8 @@ static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp)
v = roc;
}
c->last_index = (u_int64_t)(((v << 16) | seq) & 0xffffffffffffULL);
return c->last_index;
ssrc_ctx->srtp_index = (u_int64_t)(((v << 16) | seq) & 0xffffffffffffULL);
return ssrc_ctx->srtp_index;
}
void rtp_append_mki(str *s, struct crypto_context *c) {
@ -86,48 +86,21 @@ void rtp_append_mki(str *s, struct crypto_context *c) {
s->len += c->params.mki_len;
}
static int rtp_ssrc_check(const struct rtp_header *rtp, struct crypto_context *c, struct ssrc_hash *ht,
enum ssrc_dir dir)
{
struct ssrc_ctx *ssrc_ctx;
/* check last known SSRC */
if (G_LIKELY(rtp->ssrc == c->ssrc)) // XXX replace by pointer
return 0;
if (!c->ssrc) {
c->ssrc = rtp->ssrc;
return 1;
}
/* SSRC mismatch. stash away last know info */
ilog(LOG_DEBUG, "SSRC changed, updating SRTP crypto contexts");
// Find the entry for the last SSRC.
ssrc_ctx = get_ssrc_ctx(c->ssrc, ht, dir);
ssrc_ctx->srtp_index = c->last_index;
// New SSRC, set the crypto context.
c->ssrc = rtp->ssrc;
ssrc_ctx = get_ssrc_ctx(rtp->ssrc, ht, dir);
c->last_index = ssrc_ctx->srtp_index; // defaults to 0
return 1;
}
/* rfc 3711, section 3.3 */
int rtp_avp2savp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ssrc_dir dir) {
int rtp_avp2savp(str *s, struct crypto_context *c, struct ssrc_ctx *ssrc_ctx) {
struct rtp_header *rtp;
str payload, to_auth;
u_int64_t index;
int ret = 0;
if (G_UNLIKELY(!ssrc_ctx))
return -1;
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
ret = rtp_ssrc_check(rtp, c, ht, dir);
index = packet_index(c, rtp);
index = packet_index(ssrc_ctx, rtp);
/* rfc 3711 section 3.1 */
if (!c->params.session_params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, index))
@ -146,20 +119,21 @@ int rtp_avp2savp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ss
}
/* rfc 3711, section 3.3 */
int rtp_savp2avp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ssrc_dir dir) {
int rtp_savp2avp(str *s, struct crypto_context *c, struct ssrc_ctx *ssrc_ctx) {
struct rtp_header *rtp;
u_int64_t index;
str payload, to_auth, to_decrypt, auth_tag;
char hmac[20];
int ret = 0;
if (G_UNLIKELY(!ssrc_ctx))
return -1;
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
ret = rtp_ssrc_check(rtp, c, ht, dir);
index = packet_index(c, rtp);
index = packet_index(ssrc_ctx, rtp);
if (srtp_payloads(&to_auth, &to_decrypt, &auth_tag, NULL,
c->params.session_params.unauthenticated_srtp ? 0 : c->params.crypto_suite->srtp_auth_tag,
c->params.mki_len,
@ -195,7 +169,7 @@ int rtp_savp2avp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ss
goto error;
decrypt_idx:
c->last_index = index;
ssrc_ctx->srtp_index = index;
decrypt:
if (!c->params.session_params.unencrypted_srtp && crypto_decrypt_rtp(c, rtp, &to_decrypt, index))
return -1;

@ -12,6 +12,7 @@ struct crypto_context;
struct rtp_header;
struct ssrc_hash;
enum ssrc_dir;
struct ssrc_ctx;
@ -19,8 +20,8 @@ enum ssrc_dir;
const struct rtp_payload_type *rtp_payload_type(unsigned int, GHashTable *);
int rtp_avp2savp(str *, struct crypto_context *, struct ssrc_hash *, enum ssrc_dir);
int rtp_savp2avp(str *, struct crypto_context *, struct ssrc_hash *, enum ssrc_dir);
int rtp_avp2savp(str *, struct crypto_context *, struct ssrc_ctx *);
int rtp_savp2avp(str *, struct crypto_context *, struct ssrc_ctx *);
void rtp_append_mki(str *s, struct crypto_context *c);
int srtp_payloads(str *to_auth, str *to_decrypt, str *auth_tag, str *mki,

@ -6,12 +6,17 @@
static void init_ssrc_ctx(struct ssrc_ctx *c, struct ssrc_entry *parent) {
c->parent = parent;
}
static struct ssrc_entry *create_ssrc_entry(u_int32_t ssrc) {
struct ssrc_entry *ent;
ent = g_slice_alloc0(sizeof(struct ssrc_entry));
ent->ssrc = ssrc;
mutex_init(&ent->lock);
ent->payload_type = -1;
init_ssrc_ctx(&ent->input_ctx, ent);
init_ssrc_ctx(&ent->output_ctx, ent);
return ent;
}
static void add_ssrc_entry(struct ssrc_entry *ent, struct ssrc_hash *ht) {

@ -14,6 +14,8 @@ struct call;
struct call_media;
struct timeval;
struct rtp_payload_type;
struct ssrc_entry;
enum ssrc_dir;
@ -22,8 +24,10 @@ struct ssrc_hash {
rwlock_t lock;
};
struct ssrc_ctx {
struct ssrc_entry *parent;
// XXX lock this?
u_int64_t srtp_index;
u_int64_t srtp_index,
srtcp_index;
// XXX move entire crypto context in here?
};
struct ssrc_entry {
@ -36,7 +40,7 @@ struct ssrc_entry {
int payload_type; // to determine the clock rate for jitter calculations
unsigned int last_rtt; // last calculated raw rtt without rtt from opposide side
};
enum ssrc_dir {
enum ssrc_dir { // these values must not be used externally
SSRC_DIR_INPUT = G_STRUCT_OFFSET(struct ssrc_entry, input_ctx),
SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry, output_ctx),
};

@ -228,10 +228,11 @@ sub savp_sdp {
}
sub rtcp_sr {
my ($ssrc) = @_;
my @now = Time::HiRes::gettimeofday();
my $secs = $now[0] + 2208988800;
my $frac = $now[1] / 1000000 * 2**32;
my $sr = pack('CCnN NNN NN', (2 << 6) | 1, 200, 12, rand(2**32), $secs, $frac,
my $sr = pack('CCnN NNN NN', (2 << 6) | 1, 200, 12, $ssrc, $secs, $frac,
12345, rand(12345), rand(4321));
$sr .= pack('N CCCC NNNN', rand(2**32), rand(256), rand(256), rand(256), rand(256),
rand(2**32), rand(2**32), rand(2**32), rand(2**32));
@ -262,7 +263,8 @@ sub rtcp_rtpfb {
sub rtcp_avp {
my ($recv, $ctx, $ctx_o) = @_;
my $sr = rtcp_sr();
my $ssrc = $$ctx{ssrc} // ($$ctx{ssrc} = rand(2**32));
my $sr = rtcp_sr($ssrc);
my $exp = $sr;
$$recv{srtp} and $exp = rtcp_encrypt($exp, $ctx_o, 'in');
return ($sr, $exp);
@ -270,7 +272,8 @@ sub rtcp_avp {
sub rtcp_savp {
my ($recv, $ctx, $ctx_o) = @_;
my $sr = rtcp_sr();
my $ssrc = $$ctx{ssrc} // ($$ctx{ssrc} = rand(2**32));
my $sr = rtcp_sr($ssrc);
my $enc = rtcp_encrypt($sr, $ctx, 'out');
my $exp = $sr;
$$recv{srtp} and $exp = rtcp_encrypt($exp, $ctx_o, 'in');
@ -279,7 +282,8 @@ sub rtcp_savp {
sub rtcp_avpf {
my ($recv, $ctx, $ctx_o) = @_;
my $sr = rtcp_sr();
my $ssrc = $$ctx{ssrc} // ($$ctx{ssrc} = rand(2**32));
my $sr = rtcp_sr($ssrc);
my $fb = rtcp_rtpfb();
my $exp = $sr;
$$recv{avpf} and $exp .= $fb;
@ -289,7 +293,8 @@ sub rtcp_avpf {
sub rtcp_savpf {
my ($recv, $ctx, $ctx_o) = @_;
my $sr = rtcp_sr();
my $ssrc = $$ctx{ssrc} // ($$ctx{ssrc} = rand(2**32));
my $sr = rtcp_sr($ssrc);
my $fb = rtcp_rtpfb();
my $enc = rtcp_encrypt($sr . $fb, $ctx, 'out');
my $exp = $sr;

Loading…
Cancel
Save