diff --git a/daemon/call.c b/daemon/call.c index 49eb8c529..7bf77f850 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -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), diff --git a/daemon/call.h b/daemon/call.h index 01a02a11e..d1e7bf186 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -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; diff --git a/daemon/crypto.h b/daemon/crypto.h index 16e6fc448..d0663fb83 100644 --- a/daemon/crypto.h +++ b/daemon/crypto.h @@ -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; diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 42242a1e9..e072b28c0 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -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) { diff --git a/daemon/redis.c b/daemon/redis.c index f932abcc0..9aa60c795 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -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); diff --git a/daemon/rtcp.c b/daemon/rtcp.c index da0c377d9..64b47e25f 100644 --- a/daemon/rtcp.c +++ b/daemon/rtcp.c @@ -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)) diff --git a/daemon/rtcp.h b/daemon/rtcp.h index 3a41864dd..cf7e3d870 100644 --- a/daemon/rtcp.h +++ b/daemon/rtcp.h @@ -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 *); diff --git a/daemon/rtp.c b/daemon/rtp.c index 6fdb1f945..4ae11db16 100644 --- a/daemon/rtp.c +++ b/daemon/rtp.c @@ -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; diff --git a/daemon/rtp.h b/daemon/rtp.h index 6741551c9..123a3cb5f 100644 --- a/daemon/rtp.h +++ b/daemon/rtp.h @@ -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, diff --git a/daemon/ssrc.c b/daemon/ssrc.c index 82f84ecdb..a39ad11ec 100644 --- a/daemon/ssrc.c +++ b/daemon/ssrc.c @@ -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) { diff --git a/daemon/ssrc.h b/daemon/ssrc.h index 0f29506ae..f289e6529 100644 --- a/daemon/ssrc.h +++ b/daemon/ssrc.h @@ -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), }; diff --git a/tests/simulator-ng.pl b/tests/simulator-ng.pl index e112bad9e..3191c2688 100755 --- a/tests/simulator-ng.pl +++ b/tests/simulator-ng.pl @@ -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;