diff --git a/daemon/Makefile b/daemon/Makefile index ce91f6ddd..2e7877ef6 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -38,7 +38,7 @@ include ../lib/lib.Makefile SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \ bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \ crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \ - media_socket.c rtcp_xr.c homer.c recording.c statistics.c cdr.c + media_socket.c rtcp_xr.c homer.c recording.c statistics.c cdr.c ssrc.c LIBSRCS= loglib.c auxlib.c rtplib.c OBJS= $(SRCS:.c=.o) $(LIBSRCS:.c=.o) diff --git a/daemon/call.c b/daemon/call.c index 9bbb29ac0..02f151cbc 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -40,6 +40,7 @@ #include "rtplib.h" #include "cdr.h" #include "statistics.h" +#include "ssrc.h" /* also serves as array index for callstream->peers[] */ @@ -2004,6 +2005,7 @@ static void __call_free(void *p) { g_hash_table_destroy(c->tags); g_hash_table_destroy(c->viabranches); + free_ssrc_hash(&c->ssrc_hash); while (c->streams.head) { ps = g_queue_pop_head(&c->streams); @@ -2031,6 +2033,7 @@ static struct call *call_create(const str *callid, struct callmaster *m) { c->created = poller_now; c->dtls_cert = dtls_cert(); c->tos = m->conf.default_tos; + c->ssrc_hash = create_ssrc_hash(); return c; } diff --git a/daemon/call.h b/daemon/call.h index c786bb074..dae947051 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -204,6 +204,7 @@ struct local_interface; struct call_monologue; struct ice_agent; struct homer_sender; +struct ssrc_hash; typedef bencode_buffer_t call_buffer_t; @@ -367,6 +368,7 @@ struct call { GQueue stream_fds; GQueue endpoint_maps; struct dtls_cert *dtls_cert; /* for outgoing */ + struct ssrc_hash *ssrc_hash; str callid; time_t created; diff --git a/daemon/crypto.h b/daemon/crypto.h index de97ff436..16e6fc448 100644 --- a/daemon/crypto.h +++ b/daemon/crypto.h @@ -88,15 +88,10 @@ struct crypto_context { /* ? */ void *session_key_ctx[2]; - GHashTable *ssrc_hash; int have_session_key:1; }; -struct rtp_ssrc_entry { - u_int32_t ssrc; - u_int64_t index; -}; extern const struct crypto_suite *crypto_suites; extern const int num_crypto_suites; @@ -109,11 +104,6 @@ const struct crypto_suite *crypto_find_suite(const str *); int crypto_gen_session_key(struct crypto_context *, str *, unsigned char, int); void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out); -INLINE struct rtp_ssrc_entry *find_ssrc(u_int32_t, GHashTable *); -INLINE void add_ssrc_entry(struct rtp_ssrc_entry *, GHashTable *); -INLINE struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t, u_int64_t); -INLINE void free_ssrc_table(GHashTable **); -INLINE GHashTable *create_ssrc_table(void); INLINE int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header *rtp, @@ -147,7 +137,6 @@ INLINE void crypto_params_cleanup(struct crypto_params *p) { } INLINE void crypto_cleanup(struct crypto_context *c) { crypto_params_cleanup(&c->params); - free_ssrc_table(&c->ssrc_hash); if (!c->params.crypto_suite) return; if (c->params.crypto_suite->session_key_cleanup) @@ -202,31 +191,4 @@ INLINE int crypto_params_cmp(const struct crypto_params *a, const struct crypto_ -INLINE struct rtp_ssrc_entry *find_ssrc(u_int32_t ssrc, GHashTable *ht) { - return g_hash_table_lookup(ht, &ssrc); -} -INLINE void add_ssrc_entry(struct rtp_ssrc_entry *ent, GHashTable *ht) { - g_hash_table_insert(ht, &ent->ssrc, ent); -} -INLINE struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t ssrc, u_int64_t index) { - struct rtp_ssrc_entry *ent; - ent = g_slice_alloc(sizeof(struct rtp_ssrc_entry)); - ent->ssrc = ssrc; - ent->index = index; - return ent; -} -INLINE void free_ssrc_table(GHashTable **ht) { - if (!*ht) - return; - g_hash_table_destroy(*ht); - *ht = NULL; -} -INLINE void free_ssrc_entry(void *p) { - g_slice_free1(sizeof(struct rtp_ssrc_entry), p); -} -INLINE GHashTable *create_ssrc_table(void) { - return g_hash_table_new_full(uint32_hash, uint32_eq, free_ssrc_entry, NULL); -} - - #endif diff --git a/daemon/media_socket.c b/daemon/media_socket.c index de6d7e1ea..d39ed2d51 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -21,6 +21,7 @@ #include "recording.h" #include "rtplib.h" #include "rtcplib.h" +#include "ssrc.h" #ifndef PORT_RANDOM_MIN @@ -790,13 +791,13 @@ static int call_avpf2avp_rtcp(str *s, struct packet_stream *stream) { return rtcp_avpf2avp(s); } static int call_avp2savp_rtp(str *s, struct packet_stream *stream) { - return rtp_avp2savp(s, &stream->crypto); + return rtp_avp2savp(s, &stream->crypto, stream->call->ssrc_hash, SSRC_DIR_OUTPUT); } static int call_avp2savp_rtcp(str *s, struct packet_stream *stream) { return rtcp_avp2savp(s, &stream->crypto); } static int call_savp2avp_rtp(str *s, struct packet_stream *stream) { - return rtp_savp2avp(s, &stream->selected_sfd->crypto); + return rtp_savp2avp(s, &stream->selected_sfd->crypto, stream->call->ssrc_hash, SSRC_DIR_INPUT); } static int call_savp2avp_rtcp(str *s, struct packet_stream *stream) { return rtcp_savp2avp(s, &stream->selected_sfd->crypto); diff --git a/daemon/rtp.c b/daemon/rtp.c index 478aaf136..6fdb1f945 100644 --- a/daemon/rtp.c +++ b/daemon/rtp.c @@ -9,6 +9,7 @@ #include "crypto.h" #include "log.h" #include "rtplib.h" +#include "ssrc.h" @@ -85,11 +86,13 @@ 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 rtp_ssrc_entry *cur_ssrc; +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)) + if (G_LIKELY(rtp->ssrc == c->ssrc)) // XXX replace by pointer return 0; if (!c->ssrc) { c->ssrc = rtp->ssrc; @@ -98,32 +101,21 @@ static int rtp_ssrc_check(const struct rtp_header *rtp, struct crypto_context *c /* SSRC mismatch. stash away last know info */ ilog(LOG_DEBUG, "SSRC changed, updating SRTP crypto contexts"); - if (G_UNLIKELY(!c->ssrc_hash)) - c->ssrc_hash = create_ssrc_table(); // Find the entry for the last SSRC. - cur_ssrc = find_ssrc(c->ssrc, c->ssrc_hash); - // If it doesn't exist, create a new entry. - if (G_UNLIKELY(!cur_ssrc)) { - cur_ssrc = create_ssrc_entry(c->ssrc, c->last_index); - add_ssrc_entry(cur_ssrc, c->ssrc_hash); - } - else - cur_ssrc->index = c->last_index; + 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; - cur_ssrc = find_ssrc(rtp->ssrc, c->ssrc_hash); - if (G_UNLIKELY(!cur_ssrc)) - c->last_index = 0; - else - c->last_index = cur_ssrc->index; + 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) { +int rtp_avp2savp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ssrc_dir dir) { struct rtp_header *rtp; str payload, to_auth; u_int64_t index; @@ -134,7 +126,7 @@ int rtp_avp2savp(str *s, struct crypto_context *c) { if (check_session_keys(c)) return -1; - ret = rtp_ssrc_check(rtp, c); + ret = rtp_ssrc_check(rtp, c, ht, dir); index = packet_index(c, rtp); /* rfc 3711 section 3.1 */ @@ -154,7 +146,7 @@ int rtp_avp2savp(str *s, struct crypto_context *c) { } /* rfc 3711, section 3.3 */ -int rtp_savp2avp(str *s, struct crypto_context *c) { +int rtp_savp2avp(str *s, struct crypto_context *c, struct ssrc_hash *ht, enum ssrc_dir dir) { struct rtp_header *rtp; u_int64_t index; str payload, to_auth, to_decrypt, auth_tag; @@ -166,7 +158,7 @@ int rtp_savp2avp(str *s, struct crypto_context *c) { if (check_session_keys(c)) return -1; - ret = rtp_ssrc_check(rtp, c); + ret = rtp_ssrc_check(rtp, c, ht, dir); index = packet_index(c, 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, diff --git a/daemon/rtp.h b/daemon/rtp.h index 659094add..6741551c9 100644 --- a/daemon/rtp.h +++ b/daemon/rtp.h @@ -10,6 +10,8 @@ struct crypto_context; struct rtp_header; +struct ssrc_hash; +enum ssrc_dir; @@ -17,8 +19,8 @@ struct rtp_header; const struct rtp_payload_type *rtp_payload_type(unsigned int, GHashTable *); -int rtp_avp2savp(str *, struct crypto_context *); -int rtp_savp2avp(str *, struct crypto_context *); +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); 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 new file mode 100644 index 000000000..e9e144e3f --- /dev/null +++ b/daemon/ssrc.c @@ -0,0 +1,74 @@ +#include "ssrc.h" +#include +#include "aux.h" + + + +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; + return ent; +} +static void add_ssrc_entry(struct ssrc_entry *ent, struct ssrc_hash *ht) { + g_hash_table_replace(ht->ht, &ent->ssrc, ent); +} +static void free_ssrc_entry(void *p) { + g_slice_free1(sizeof(struct ssrc_entry), p); +} + + +struct ssrc_entry *find_ssrc(u_int32_t ssrc, struct ssrc_hash *ht) { + rwlock_lock_r(&ht->lock); + struct ssrc_entry *ret = g_hash_table_lookup(ht->ht, &ssrc); + rwlock_unlock_r(&ht->lock); + return ret; +} +struct ssrc_entry *get_ssrc(u_int32_t ssrc, struct ssrc_hash *ht /* , int *created */) { + struct ssrc_entry *ent; + +restart: + ent = find_ssrc(ssrc, ht); + if (G_LIKELY(ent)) { +// if (created) +// *created = 0; + return ent; + } + + ent = create_ssrc_entry(ssrc); + + rwlock_lock_w(&ht->lock); + if (g_hash_table_lookup(ht->ht, &ssrc)) { + // preempted + rwlock_unlock_w(&ht->lock); + free_ssrc_entry(ent); + goto restart; + } + add_ssrc_entry(ent, ht); + rwlock_unlock_w(&ht->lock); +// if (created) +// *created = 1; + return ent; +} +void free_ssrc_hash(struct ssrc_hash **ht) { + if (!*ht) + return; + g_hash_table_destroy((*ht)->ht); + g_slice_free1(sizeof(**ht), *ht); + *ht = NULL; +} + + +struct ssrc_hash *create_ssrc_hash(void) { + struct ssrc_hash *ret; + ret = g_slice_alloc0(sizeof(*ret)); + ret->ht = g_hash_table_new_full(uint32_hash, uint32_eq, NULL, free_ssrc_entry); + rwlock_init(&ret->lock); + return ret; +} + +struct ssrc_ctx *get_ssrc_ctx(u_int32_t ssrc, struct ssrc_hash *ht, enum ssrc_dir dir) { + struct ssrc_entry *s = get_ssrc(ssrc, ht /* , NULL */); + return ((void *) s) + dir; +} + diff --git a/daemon/ssrc.h b/daemon/ssrc.h new file mode 100644 index 000000000..ac88ee487 --- /dev/null +++ b/daemon/ssrc.h @@ -0,0 +1,47 @@ +#ifndef _SSRC_H_ +#define _SSRC_H_ + + +#include +#include +#include "compat.h" +#include "aux.h" + + + + +struct ssrc_hash { + GHashTable *ht; + rwlock_t lock; +}; +struct ssrc_ctx { + // XXX lock this? + u_int64_t srtp_index; + // XXX move entire crypto context in here? +}; +struct ssrc_entry { + // XXX lock this? + u_int32_t ssrc; + struct ssrc_ctx input_ctx, + output_ctx; +}; +enum ssrc_dir { + SSRC_DIR_INPUT = G_STRUCT_OFFSET(struct ssrc_entry, input_ctx), + SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry, output_ctx), +}; + + + + +void free_ssrc_hash(struct ssrc_hash **); +struct ssrc_hash *create_ssrc_hash(void); + +struct ssrc_entry *find_ssrc(u_int32_t, struct ssrc_hash *); // returns NULL if not found +struct ssrc_entry *get_ssrc(u_int32_t, struct ssrc_hash * /* , int *created */); // creates new entry if not found +//void add_ssrc_entry(struct ssrc_entry *, struct ssrc_hash *); // XXX static +//struct ssrc_entry *create_ssrc_entry(u_int32_t); +struct ssrc_ctx *get_ssrc_ctx(u_int32_t, struct ssrc_hash *, enum ssrc_dir); // creates new entry if not found + + + +#endif