Implement true negotiation for DatagramTransport with fallback to RTP.
In short, the caller places a x-opaque line in SDP for each m= section that uses datagram transport. If the answerer supports datagram transport, it will parse this line and create a datagram transport. It will then echo the x-opaque line into the answer (to indicate that it accepted use of datagram transport). If the offer and answer contain exactly the same x-opaque line, both peers will use datagram transport. If the x-opaque line is omitted from the answer (or is different in the answer) they will fall back to RTP. Note that a different x-opaque line in the answer means the answerer did not understand something in the negotiation proto. Since WebRTC cannot know what was misunderstood, or whether it's still possible to use the datagram transport, it must fall back to RTP. This may change in the future, possibly by passing the answer to the datagram transport, but it's good enough for now. Negotiation consists of four parts: 1. DatagramTransport exposes transport parameters for both client and server perspectives. The client just echoes what it received from the server (modulo any fields it might not have understood). 2. SDP adds a x-opaque line for opaque transport parameters. Identical to x-mt, but this is specific to datagram transport and goes in each m= section, and appears in the answer as well as the offer. - This is propagated to Jsep as part of the TransportDescription. - SDP files: transport_description.h,cc, transport_description_factory.h,cc, media_session.cc, webrtc_sdp.cc 3. JsepTransport/Controller: - Exposes opaque parameters for each mid (m= section). On offerer, this means pre-allocating a datagram transport and getting its parameters. On the answerer, this means echoing the offerer's parameters. - Uses a composite RTP transport to receive from either default RTP or datagram transport until both offer and answer arrive. - If a provisional answer arrives, sets the composite to send on the provisionally selected transport. - Once both offer and answer are set, deletes the unneeded transports and keeps whichever transport is selected. 4. PeerConnection pulls transport parameters out of Jsep and adds them to SDP. Bug: webrtc:9719 Change-Id: Id8996eb1871e79d93b7923a5d7eb3431548c798d Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140700 Commit-Queue: Bjorn Mellem <mellem@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Reviewed-by: Anton Sukhanov <sukhanov@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28182}
This commit is contained in:

committed by
Commit Bot

parent
9e78458b3f
commit
71c6482baf
@ -79,7 +79,8 @@ TransportDescription::TransportDescription(const TransportDescription& from)
|
||||
ice_pwd(from.ice_pwd),
|
||||
ice_mode(from.ice_mode),
|
||||
connection_role(from.connection_role),
|
||||
identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())) {}
|
||||
identity_fingerprint(CopyFingerprint(from.identity_fingerprint.get())),
|
||||
opaque_parameters(from.opaque_parameters) {}
|
||||
|
||||
TransportDescription::~TransportDescription() = default;
|
||||
|
||||
@ -96,6 +97,7 @@ TransportDescription& TransportDescription::operator=(
|
||||
connection_role = from.connection_role;
|
||||
|
||||
identity_fingerprint.reset(CopyFingerprint(from.identity_fingerprint.get()));
|
||||
opaque_parameters = from.opaque_parameters;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "p2p/base/p2p_constants.h"
|
||||
#include "rtc_base/ssl_fingerprint.h"
|
||||
|
||||
@ -87,6 +88,28 @@ constexpr auto* ICE_OPTION_RENOMINATION = "renomination";
|
||||
bool StringToConnectionRole(const std::string& role_str, ConnectionRole* role);
|
||||
bool ConnectionRoleToString(const ConnectionRole& role, std::string* role_str);
|
||||
|
||||
// Parameters for an opaque transport protocol which may be plugged into WebRTC.
|
||||
struct OpaqueTransportParameters {
|
||||
// Protocol used by this opaque transport. Two endpoints that support the
|
||||
// same protocol are expected to be able to understand the contents of each
|
||||
// others' |parameters| fields. If those parameters are compatible, the
|
||||
// endpoints are expected to use this transport protocol.
|
||||
std::string protocol;
|
||||
|
||||
// Opaque parameters for this transport. These parameters are serialized in a
|
||||
// manner determined by the |protocol|. They can be parsed and understood by
|
||||
// the plugin that supports |protocol|.
|
||||
std::string parameters;
|
||||
|
||||
bool operator==(const OpaqueTransportParameters& other) const {
|
||||
return protocol == other.protocol && parameters == other.parameters;
|
||||
}
|
||||
|
||||
bool operator!=(const OpaqueTransportParameters& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct TransportDescription {
|
||||
TransportDescription();
|
||||
TransportDescription(const std::vector<std::string>& transport_options,
|
||||
@ -133,6 +156,7 @@ struct TransportDescription {
|
||||
ConnectionRole connection_role;
|
||||
|
||||
std::unique_ptr<rtc::SSLFingerprint> identity_fingerprint;
|
||||
absl::optional<OpaqueTransportParameters> opaque_parameters;
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
@ -55,6 +55,8 @@ std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateOffer(
|
||||
}
|
||||
}
|
||||
|
||||
desc->opaque_parameters = options.opaque_parameters;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
@ -108,6 +110,13 @@ std::unique_ptr<TransportDescription> TransportDescriptionFactory::CreateAnswer(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Answers may only attach opaque parameters that exactly match parameters
|
||||
// present in the offer. If the answerer cannot fully understand or accept
|
||||
// the offered transport, it must reject it and fall back.
|
||||
if (offer->opaque_parameters == options.opaque_parameters) {
|
||||
desc->opaque_parameters = options.opaque_parameters;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,9 @@ struct TransportOptions {
|
||||
// If true, ICE renomination is supported and will be used if it is also
|
||||
// supported by the remote side.
|
||||
bool enable_ice_renomination = false;
|
||||
|
||||
// Opaque parameters for plug-in transports.
|
||||
absl::optional<OpaqueTransportParameters> opaque_parameters;
|
||||
};
|
||||
|
||||
// Creates transport descriptions according to the supplied configuration.
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
using cricket::OpaqueTransportParameters;
|
||||
using cricket::TransportDescription;
|
||||
using cricket::TransportDescriptionFactory;
|
||||
using cricket::TransportOptions;
|
||||
@ -207,6 +208,97 @@ TEST_F(TransportDescriptionFactoryTest, TestOfferDtlsReofferDtls) {
|
||||
CheckDesc(desc.get(), "", old_desc->ice_ufrag, old_desc->ice_pwd, digest_alg);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest, TestOfferOpaqueTransportParameters) {
|
||||
OpaqueTransportParameters params;
|
||||
params.protocol = "fake";
|
||||
params.parameters = "foobar";
|
||||
|
||||
TransportOptions options;
|
||||
options.opaque_parameters = params;
|
||||
|
||||
std::unique_ptr<TransportDescription> desc =
|
||||
f1_.CreateOffer(options, NULL, &ice_credentials_);
|
||||
|
||||
CheckDesc(desc.get(), "", "", "", "");
|
||||
EXPECT_EQ(desc->opaque_parameters, params);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest, TestAnswerOpaqueTransportParameters) {
|
||||
OpaqueTransportParameters params;
|
||||
params.protocol = "fake";
|
||||
params.parameters = "foobar";
|
||||
|
||||
TransportOptions options;
|
||||
options.opaque_parameters = params;
|
||||
|
||||
std::unique_ptr<TransportDescription> offer =
|
||||
f1_.CreateOffer(options, NULL, &ice_credentials_);
|
||||
std::unique_ptr<TransportDescription> answer =
|
||||
f2_.CreateAnswer(offer.get(), options, true, NULL, &ice_credentials_);
|
||||
|
||||
CheckDesc(answer.get(), "", "", "", "");
|
||||
EXPECT_EQ(answer->opaque_parameters, params);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest, TestAnswerNoOpaqueTransportParameters) {
|
||||
OpaqueTransportParameters params;
|
||||
params.protocol = "fake";
|
||||
params.parameters = "foobar";
|
||||
|
||||
TransportOptions options;
|
||||
options.opaque_parameters = params;
|
||||
|
||||
std::unique_ptr<TransportDescription> offer =
|
||||
f1_.CreateOffer(options, NULL, &ice_credentials_);
|
||||
std::unique_ptr<TransportDescription> answer = f2_.CreateAnswer(
|
||||
offer.get(), TransportOptions(), true, NULL, &ice_credentials_);
|
||||
|
||||
CheckDesc(answer.get(), "", "", "", "");
|
||||
EXPECT_EQ(answer->opaque_parameters, absl::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest,
|
||||
TestAnswerDifferentOpaqueTransportParameters) {
|
||||
OpaqueTransportParameters offer_params;
|
||||
offer_params.protocol = "fake";
|
||||
offer_params.parameters = "foobar";
|
||||
|
||||
TransportOptions options;
|
||||
options.opaque_parameters = offer_params;
|
||||
|
||||
std::unique_ptr<TransportDescription> offer =
|
||||
f1_.CreateOffer(options, NULL, &ice_credentials_);
|
||||
|
||||
OpaqueTransportParameters answer_params;
|
||||
answer_params.protocol = "fake";
|
||||
answer_params.parameters = "baz";
|
||||
|
||||
options.opaque_parameters = answer_params;
|
||||
std::unique_ptr<TransportDescription> answer =
|
||||
f2_.CreateAnswer(offer.get(), options, true, NULL, &ice_credentials_);
|
||||
|
||||
CheckDesc(answer.get(), "", "", "", "");
|
||||
EXPECT_EQ(answer->opaque_parameters, absl::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest,
|
||||
TestAnswerNoOpaqueTransportParametersInOffer) {
|
||||
std::unique_ptr<TransportDescription> offer =
|
||||
f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
|
||||
|
||||
OpaqueTransportParameters params;
|
||||
params.protocol = "fake";
|
||||
params.parameters = "foobar";
|
||||
|
||||
TransportOptions options;
|
||||
options.opaque_parameters = params;
|
||||
std::unique_ptr<TransportDescription> answer =
|
||||
f2_.CreateAnswer(offer.get(), options, true, NULL, &ice_credentials_);
|
||||
|
||||
CheckDesc(answer.get(), "", "", "", "");
|
||||
EXPECT_EQ(answer->opaque_parameters, absl::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(TransportDescriptionFactoryTest, TestAnswerDefault) {
|
||||
std::unique_ptr<TransportDescription> offer =
|
||||
f1_.CreateOffer(TransportOptions(), NULL, &ice_credentials_);
|
||||
|
Reference in New Issue
Block a user