From aa5bae977720d3c67cee214c0113dd9c5a613f74 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 7 Apr 2014 11:58:59 -0400 Subject: [PATCH] implement experimental passthrough relay mode --- daemon/call.c | 33 +++++++++++++++++++++++++++++++-- daemon/call.h | 3 +++ daemon/sdp.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 6900a2225..5731ef44d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -441,6 +441,8 @@ static void determine_handler(struct packet_stream *in, const struct packet_stre if (PS_ISSET(in, HAS_HANDLER)) return; + if (MEDIA_ISSET(in->media, PASSTHRU)) + goto noop; if (!in->media->protocol) goto err; @@ -465,6 +467,7 @@ done: err: ilog(LOG_WARNING, "Unknown transport protocol encountered"); +noop: in->handler = &__sh_noop; goto done; } @@ -1566,6 +1569,29 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru return 0; } +static void __ice_offer(const struct sdp_ng_flags *flags, struct call_media *this, + struct call_media *other) +{ + if (!flags) + return; + + /* we offer ICE by default */ + if (flags->opmode == OP_OFFER) { + if (!MEDIA_ISSET(this, INITIALIZED)) + MEDIA_SET(this, ICE); + } + if (flags->ice_remove) + MEDIA_CLEAR(this, ICE); + + /* special case: if doing ICE on both sides and ice_force is not set, we cannot + * be sure that media will pass through us, so we have to disable certain features */ + if (MEDIA_ISSET(this, ICE) && MEDIA_ISSET(other, ICE) && !flags->ice_force) { + ilog(LOG_DEBUG, "enabling passthrough mode"); + MEDIA_SET(this, PASSTHRU); + MEDIA_SET(other, PASSTHRU); + } +} + /* generates SDES parametes for outgoing SDP, which is our media "out" direction */ static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_media *this, struct call_media *other) @@ -1576,7 +1602,7 @@ static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_medi if (!flags) return; - if (!this->protocol || !this->protocol->srtp) { + if (!this->protocol || !this->protocol->srtp || MEDIA_ISSET(this, PASSTHRU)) { cp->crypto_suite = NULL; MEDIA_CLEAR(this, DTLS); MEDIA_CLEAR(this, SDES); @@ -1764,7 +1790,7 @@ int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, /* copy parameters advertised by the sender of this message */ bf_copy_same(&other_media->media_flags, &sp->sp_flags, - SP_FLAG_RTCP_MUX | SP_FLAG_ASYMMETRIC); + SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_ICE); crypto_params_copy(&other_media->sdes_in.params, &sp->crypto); other_media->sdes_in.tag = sp->sdes_tag; @@ -1789,6 +1815,9 @@ int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, && other_media->fingerprint.hash_func) MEDIA_SET(other_media, DTLS); + /* ICE negotiation */ + __ice_offer(flags, media, other_media); + /* control rtcp-mux */ __rtcp_mux_logic(flags, media, other_media); diff --git a/daemon/call.h b/daemon/call.h index 81844f176..be50663d5 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -76,6 +76,7 @@ struct call_monologue; #define SHARED_FLAG_RTCP_MUX 0x00000010 #define SHARED_FLAG_SETUP_ACTIVE 0x00000020 #define SHARED_FLAG_SETUP_PASSIVE 0x00000040 +#define SHARED_FLAG_ICE 0x00000080 /* struct stream_params */ #define SP_FLAG_NO_RTCP 0x00010000 @@ -86,6 +87,7 @@ struct call_monologue; #define SP_FLAG_ASYMMETRIC SHARED_FLAG_ASYMMETRIC #define SP_FLAG_SETUP_ACTIVE SHARED_FLAG_SETUP_ACTIVE #define SP_FLAG_SETUP_PASSIVE SHARED_FLAG_SETUP_PASSIVE +#define SP_FLAG_ICE SHARED_FLAG_ICE /* struct packet_stream */ #define PS_FLAG_RTP 0x00010000 @@ -112,6 +114,7 @@ struct call_monologue; #define MEDIA_FLAG_SETUP_ACTIVE SHARED_FLAG_SETUP_ACTIVE #define MEDIA_FLAG_SETUP_PASSIVE SHARED_FLAG_SETUP_PASSIVE #define MEDIA_FLAG_PASSTHRU 0x00100000 +#define MEDIA_FLAG_ICE SHARED_FLAG_ICE /* access macros */ #define SP_ISSET(p, f) bf_isset(&(p)->sp_flags, SP_FLAG_ ## f) diff --git a/daemon/sdp.c b/daemon/sdp.c index 1e8fd71b6..b9fc9eedb 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -1031,6 +1031,10 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl sp->fingerprint.hash_func->num_bytes); } + /* a=candidate */ + if (attr_get_by_id(&media->attributes, ATTR_CANDIDATE)) + SP_SET(sp, ICE); + /* determine RTCP endpoint */ if (attr_get_by_id(&media->attributes, ATTR_RTCP_MUX)) { @@ -1356,23 +1360,31 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media * case ATTR_ICE: case ATTR_ICE_UFRAG: case ATTR_CANDIDATE: + if (MEDIA_ISSET(media, PASSTHRU)) + break; if (!flags->ice_remove && !flags->ice_force) break; goto strip; case ATTR_RTCP: case ATTR_RTCP_MUX: - case ATTR_EXTMAP: - case ATTR_CRYPTO: case ATTR_INACTIVE: case ATTR_SENDONLY: case ATTR_RECVONLY: case ATTR_SENDRECV: + goto strip; + + case ATTR_EXTMAP: + case ATTR_CRYPTO: case ATTR_FINGERPRINT: case ATTR_SETUP: + if (MEDIA_ISSET(media, PASSTHRU)) + break; goto strip; case ATTR_MID: + if (MEDIA_ISSET(media, PASSTHRU)) + break; a = attr_get_by_id(&sdp->session->attributes, ATTR_GROUP); if (a && a->u.group.semantics == GROUP_BUNDLE) goto strip; @@ -1499,7 +1511,7 @@ static void insert_dtls(struct call_media *media, struct sdp_chopper *chop) { const char *actpass; struct call *call = media->call; - if (!call->dtls_cert || !MEDIA_ISSET(media, DTLS)) + if (!call->dtls_cert || !MEDIA_ISSET(media, DTLS) || MEDIA_ISSET(media, PASSTHRU)) return; hf = call->dtls_cert->fingerprint.hash_func; @@ -1538,7 +1550,7 @@ static void insert_crypto(struct call_media *media, struct sdp_chopper *chop) { struct crypto_params *cp = &media->sdes_out.params; unsigned long long ull; - if (!cp->crypto_suite || !MEDIA_ISSET(media, SDES)) + if (!cp->crypto_suite || !MEDIA_ISSET(media, SDES) || MEDIA_ISSET(media, PASSTHRU)) return; p = b64_buf; @@ -1616,12 +1628,14 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu goto error; } - if (process_session_attributes(chop, &session->attributes, flags)) - goto error; + if (!MEDIA_ISSET(call_media, PASSTHRU)) { + if (process_session_attributes(chop, &session->attributes, flags)) + goto error; - if (do_ice) { - copy_up_to_end_of(chop, &session->s); - chopper_append_c(chop, "a=ice-lite\r\n"); + if (do_ice) { + copy_up_to_end_of(chop, &session->s); + chopper_append_c(chop, "a=ice-lite\r\n"); + } } media_index = 1; @@ -1696,7 +1710,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu insert_crypto(call_media, chop); insert_dtls(call_media, chop); - if (do_ice) { + if (do_ice && !MEDIA_ISSET(call_media, PASSTHRU)) { if (!call_media->ice_ufrag.s) { create_random_ice_string(call, &call_media->ice_ufrag, 8); create_random_ice_string(call, &call_media->ice_pwd, 28);