From 1d34c402763c73f6125bdae7f39cf1b739a94128 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 13 Nov 2020 10:10:32 -0500 Subject: [PATCH] TT#101201 support optional ICE-lite mode closes #1106 Change-Id: I4a83ed2630889d8b17a0c40d971ec7946c1ed3a2 --- README.md | 16 ++++++++++++++++ daemon/call.c | 31 +++++++++++++++++++++++++++---- daemon/call_interfaces.c | 31 +++++++++++++++++++++++++++++++ daemon/ice.c | 32 ++++++++++++++++++++------------ daemon/sdp.c | 3 +++ include/call.h | 1 + include/call_interfaces.h | 6 ++++++ include/ice.h | 1 + utils/rtpengine-ng-client | 3 ++- 9 files changed, 107 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c9838d7c5..2b64a233a 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ the following additional features are available: + Bridging between ICE-enabled and ICE-unaware user agents + Optionally acting only as additional ICE relay/candidate + Optionally forcing relay of media streams by removing other ICE candidates + + Optionally act as an "ICE lite" peer only - SRTP (RFC 3711) support: + Support for SDES (RFC 4568) and DTLS-SRTP (RFC 5764) + AES-CM and AES-F8 ciphers, both in userspace and in kernel @@ -897,6 +898,21 @@ Optionally included keys are: This flag operates independently of the `replace` flags. +* `ICE-lite` + + Contains a string which must be one of the following values: + + - `forward` to enable "ICE lite" mode towards the peer that this offer is sent to. + + - `backward` to enable "ICE lite" mode towards the peer that has sent this offer. + + - `both` to enable "ICE lite" towards both peers. + + - `off` to disable "ICE lite" towards both peers and revert to full ICE support. + + The default (keyword not present at all) is to use full ICE support, or to leave the previously + set "ICE lite" mode unchanged. This keyword is valid in `offer` messages only. + * `transport protocol` The transport protocol specified in the SDP body is to be rewritten to the string value given here. diff --git a/daemon/call.c b/daemon/call.c index 7239ea5f2..4a125a5b1 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1282,23 +1282,46 @@ static void __ice_offer(const struct sdp_ng_flags *flags, struct call_media *thi } } + switch (flags->ice_lite_option) { + case ICE_LITE_OFF: + MEDIA_CLEAR(this, ICE_LITE_SELF); + MEDIA_CLEAR(other, ICE_LITE_SELF); + break; + case ICE_LITE_FWD: + MEDIA_SET(this, ICE_LITE_SELF); + MEDIA_CLEAR(other, ICE_LITE_SELF); + break; + case ICE_LITE_BKW: + MEDIA_CLEAR(this, ICE_LITE_SELF); + MEDIA_SET(other, ICE_LITE_SELF); + break; + case ICE_LITE_BOTH: + MEDIA_SET(this, ICE_LITE_SELF); + MEDIA_SET(other, ICE_LITE_SELF); + break; + }; + /* determine roles (even if we don't actually do ICE) */ /* this = receiver, other = sender */ /* ICE_CONTROLLING is from our POV, the other ICE flags are from peer's POV */ - if (MEDIA_ISSET(this, ICE_LITE_PEER)) + if (MEDIA_ISSET(this, ICE_LITE_PEER) && !MEDIA_ISSET(this, ICE_LITE_SELF)) MEDIA_SET(this, ICE_CONTROLLING); else if (!MEDIA_ISSET(this, INITIALIZED)) { - if (flags->opmode == OP_OFFER) + if (MEDIA_ISSET(this, ICE_LITE_SELF)) + MEDIA_CLEAR(this, ICE_CONTROLLING); + else if (flags->opmode == OP_OFFER) MEDIA_SET(this, ICE_CONTROLLING); else MEDIA_CLEAR(this, ICE_CONTROLLING); } /* roles are reversed for the other side */ - if (MEDIA_ISSET(other, ICE_LITE_PEER)) + if (MEDIA_ISSET(other, ICE_LITE_PEER) && !MEDIA_ISSET(other, ICE_LITE_SELF)) MEDIA_SET(other, ICE_CONTROLLING); else if (!MEDIA_ISSET(other, INITIALIZED)) { - if (flags->opmode == OP_OFFER) + if (MEDIA_ISSET(other, ICE_LITE_SELF)) + MEDIA_CLEAR(other, ICE_CONTROLLING); + else if (flags->opmode == OP_OFFER) MEDIA_CLEAR(other, ICE_CONTROLLING); else MEDIA_SET(other, ICE_CONTROLLING); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 5d71a3ce1..6318860f6 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -949,6 +949,37 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu } } + if (bencode_dictionary_get_str(input, "ICE-lite", &s)) { + switch (__csh_lookup(&s)) { + case CSH_LOOKUP("off"): + case CSH_LOOKUP("none"): + case CSH_LOOKUP("no"): + out->ice_lite_option = ICE_LITE_OFF; + break; + case CSH_LOOKUP("forward"): + case CSH_LOOKUP("offer"): + case CSH_LOOKUP("fwd"): + case CSH_LOOKUP("fw"): + out->ice_lite_option = ICE_LITE_FWD; + break; + case CSH_LOOKUP("backward"): + case CSH_LOOKUP("backwards"): + case CSH_LOOKUP("reverse"): + case CSH_LOOKUP("answer"): + case CSH_LOOKUP("back"): + case CSH_LOOKUP("bkw"): + case CSH_LOOKUP("bk"): + out->ice_lite_option = ICE_LITE_BKW; + break; + case CSH_LOOKUP("both"): + out->ice_lite_option = ICE_LITE_BOTH; + break; + default: + ilog(LOG_WARN, "Unknown 'ICE-lite' flag encountered: '" STR_FORMAT "'", + STR_FMT(&s)); + } + } + if (bencode_dictionary_get_str(input, "DTLS", &s)) { switch (__csh_lookup(&s)) { case CSH_LOOKUP("passive"): diff --git a/daemon/ice.c b/daemon/ice.c index a29591b36..a9ee10276 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -237,6 +237,7 @@ static void __ice_agent_initialize(struct ice_agent *ag) { ag->foundation_hash = g_hash_table_new(__found_hash, __found_equal); ag->agent_flags = 0; bf_copy(&ag->agent_flags, ICE_AGENT_CONTROLLING, &media->media_flags, MEDIA_FLAG_ICE_CONTROLLING); + bf_copy(&ag->agent_flags, ICE_AGENT_LITE_SELF, &media->media_flags, MEDIA_FLAG_ICE_LITE_SELF); ag->logical_intf = media->logical_intf; ag->desired_family = media->desired_family; ag->nominated_pairs = g_tree_new(__pair_prio_cmp); @@ -579,6 +580,9 @@ static void __do_ice_check(struct ice_candidate_pair *pair) { struct ice_agent *ag = pair->agent; u_int32_t prio, transact[3]; + if (AGENT_ISSET(ag, LITE_SELF)) + PAIR_SET(pair, SUCCEEDED); + if (PAIR_ISSET(pair, SUCCEEDED) && !PAIR_ISSET(pair, TO_USE)) return; @@ -1096,19 +1100,23 @@ int ice_request(struct stream_fd *sfd, const endpoint_t *src, mutex_unlock(&ag->lock); - /* determine role conflict */ - if (attrs->controlling && AGENT_ISSET(ag, CONTROLLING)) { - if (tie_breaker >= attrs->tiebreaker) - return -2; - else - __role_change(ag, 0); - } - else if (attrs->controlled && !AGENT_ISSET(ag, CONTROLLING)) { - if (tie_breaker >= attrs->tiebreaker) - __role_change(ag, 1); - else - return -2; + if (!AGENT_ISSET(ag, LITE_SELF)) { + /* determine role conflict */ + if (attrs->controlling && AGENT_ISSET(ag, CONTROLLING)) { + if (tie_breaker >= attrs->tiebreaker) + return -2; + else + __role_change(ag, 0); + } + else if (attrs->controlled && !AGENT_ISSET(ag, CONTROLLING)) { + if (tie_breaker >= attrs->tiebreaker) + __role_change(ag, 1); + else + return -2; + } } + else + PAIR_SET(pair, SUCCEEDED); if (PAIR_ISSET(pair, SUCCEEDED)) diff --git a/daemon/sdp.c b/daemon/sdp.c index 371cbf65c..16afc03f0 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -2370,6 +2370,9 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu chopper_append_c(chop, "\r\n"); } + if (MEDIA_ISSET(call_media, ICE) && MEDIA_ISSET(call_media, ICE_LITE_SELF)) + chopper_append_c(chop, "a=ice-lite\r\n"); + media_index = 1; for (k = session->media_streams.head; k; k = k->next) { diff --git a/include/call.h b/include/call.h index 1e64bf0c8..4e125a09c 100644 --- a/include/call.h +++ b/include/call.h @@ -153,6 +153,7 @@ enum call_type { #define MEDIA_FLAG_PTIME_OVERRIDE 0x01000000 #define MEDIA_FLAG_RTCP_FB SHARED_FLAG_RTCP_FB #define MEDIA_FLAG_GENERATOR 0x02000000 +#define MEDIA_FLAG_ICE_LITE_SELF 0x04000000 /* access macros */ #define SP_ISSET(p, f) bf_isset(&(p)->sp_flags, SP_FLAG_ ## f) diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 88ccc0677..1601fdee7 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -54,6 +54,12 @@ struct sdp_ng_flags { ICE_FORCE_RELAY, ICE_OPTIONAL, } ice_option:3; + enum { + ICE_LITE_OFF = 0, + ICE_LITE_FWD, + ICE_LITE_BKW, + ICE_LITE_BOTH, + } ice_lite_option:2; int asymmetric:1, protocol_accept:1, no_redis_update:1, diff --git a/include/ice.h b/include/ice.h index c96356806..7ca2b1495 100644 --- a/include/ice.h +++ b/include/ice.h @@ -30,6 +30,7 @@ #define ICE_AGENT_CONTROLLING 0x0004 #define ICE_AGENT_NOMINATING 0x0008 #define ICE_AGENT_USABLE 0x0010 +#define ICE_AGENT_LITE_SELF 0x0020 #define ICE_PAIR_FROZEN 0x0001 #define ICE_PAIR_IN_PROGRESS 0x0002 diff --git a/utils/rtpengine-ng-client b/utils/rtpengine-ng-client index 09ce66b7c..d115ec789 100755 --- a/utils/rtpengine-ng-client +++ b/utils/rtpengine-ng-client @@ -77,13 +77,14 @@ GetOptions( 'symmetric-codecs' => \$options{'symmetric codecs'}, 'asymmetric-codecs' => \$options{'asymmetric codecs'}, 'DTLS-fingerprint=s' => \$options{'DTLS-fingerprint'}, + 'ICE-lite=s' => \$options{'ICE-lite'}, ) or die; my $cmd = shift(@ARGV) or die; my %packet = (command => $cmd); -for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint')) { +for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint,ICE-lite')) { defined($options{$x}) and $packet{$x} = \$options{$x}; } for my $x (split(/,/, 'TOS,delete-delay')) {