TurnCustomizer - an interface for modifying stun messages sent by TurnPort

This patch adds an interface that allows modification of stun messages
sent by TurnPort. A user can inject a TurnCustomizer on the RTCConfig
and the TurnCustomizer will be invoked by TurnPort before sending
message. This allows user to e.g add custom attributes as described
in rtf5389.

BUG=webrtc:8313

Change-Id: I6f4333e9f8ff7fd20f32677be19285f15e1180b6
Reviewed-on: https://webrtc-review.googlesource.com/7618
Reviewed-by: Guido Urdaneta <guidou@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20233}
This commit is contained in:
Jonas Oreland 2017-10-10 14:01:40 +02:00 committed by Commit Bot
parent 2ff7ecfceb
commit bdcee28ee9
27 changed files with 559 additions and 36 deletions

View File

@ -61,6 +61,7 @@ rtc_static_library("libjingle_peerconnection_api") {
"rtpsenderinterface.h", "rtpsenderinterface.h",
"statstypes.cc", "statstypes.cc",
"statstypes.h", "statstypes.h",
"turncustomizer.h",
"umametrics.h", "umametrics.h",
"videosourceproxy.h", "videosourceproxy.h",
] ]

View File

@ -83,6 +83,7 @@
#include "api/rtpsenderinterface.h" #include "api/rtpsenderinterface.h"
#include "api/stats/rtcstatscollectorcallback.h" #include "api/stats/rtcstatscollectorcallback.h"
#include "api/statstypes.h" #include "api/statstypes.h"
#include "api/turncustomizer.h"
#include "api/umametrics.h" #include "api/umametrics.h"
#include "call/callfactoryinterface.h" #include "call/callfactoryinterface.h"
#include "logging/rtc_event_log/rtc_event_log_factory_interface.h" #include "logging/rtc_event_log/rtc_event_log_factory_interface.h"
@ -474,6 +475,12 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
// interval specified in milliseconds by the uniform distribution [a, b]. // interval specified in milliseconds by the uniform distribution [a, b].
rtc::Optional<rtc::IntervalRange> ice_regather_interval_range; rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
// Optional TurnCustomizer.
// With this class one can modify outgoing TURN messages.
// The object passed in must remain valid until PeerConnection::Close() is
// called.
webrtc::TurnCustomizer* turn_customizer = nullptr;
// //
// Don't forget to update operator== if adding something. // Don't forget to update operator== if adding something.
// //

46
api/turncustomizer.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_TURNCUSTOMIZER_H_
#define API_TURNCUSTOMIZER_H_
#include <stdlib.h>
namespace cricket {
class PortInterface;
class StunMessage;
} // namespace cricket
namespace webrtc {
class TurnCustomizer {
public:
// This is called before a TURN message is sent.
// This could be used to add implementation specific attributes to a request.
virtual void MaybeModifyOutgoingStunMessage(
cricket::PortInterface* port,
cricket::StunMessage* message) = 0;
// TURN can send data using channel data messages or Send indication.
// This method should return false if |data| should be sent using
// a Send indication instead of a ChannelData message, even if a
// channel is bound.
virtual bool AllowChannelData(cricket::PortInterface* port,
const void* data,
size_t size,
bool payload) = 0;
virtual ~TurnCustomizer() {}
};
} // namespace webrtc
#endif // API_TURNCUSTOMIZER_H_

View File

@ -148,6 +148,7 @@ if (rtc_include_tests) {
"base/mockicetransport.h", "base/mockicetransport.h",
"base/testrelayserver.h", "base/testrelayserver.h",
"base/teststunserver.h", "base/teststunserver.h",
"base/testturncustomizer.h",
"base/testturnserver.h", "base/testturnserver.h",
] ]
deps = [ deps = [

View File

@ -536,7 +536,8 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
return TurnPort::Create( return TurnPort::Create(
&main_, socket_factory, MakeNetwork(addr), 0, 0, username_, password_, &main_, socket_factory, MakeNetwork(addr), 0, 0, username_, password_,
ProtocolAddress(server_addr, int_proto), kRelayCredentials, 0, ProtocolAddress(server_addr, int_proto), kRelayCredentials, 0,
std::string(), std::vector<std::string>(), std::vector<std::string>()); std::string(), std::vector<std::string>(), std::vector<std::string>(),
nullptr);
} }
RelayPort* CreateGturnPort(const SocketAddress& addr, RelayPort* CreateGturnPort(const SocketAddress& addr,
ProtocolType int_proto, ProtocolType ext_proto) { ProtocolType int_proto, ProtocolType ext_proto) {

View File

@ -33,7 +33,8 @@ bool PortAllocator::SetConfiguration(
const ServerAddresses& stun_servers, const ServerAddresses& stun_servers,
const std::vector<RelayServerConfig>& turn_servers, const std::vector<RelayServerConfig>& turn_servers,
int candidate_pool_size, int candidate_pool_size,
bool prune_turn_ports) { bool prune_turn_ports,
webrtc::TurnCustomizer* turn_customizer) {
bool ice_servers_changed = bool ice_servers_changed =
(stun_servers != stun_servers_ || turn_servers != turn_servers_); (stun_servers != stun_servers_ || turn_servers != turn_servers_);
stun_servers_ = stun_servers; stun_servers_ = stun_servers;
@ -62,6 +63,8 @@ bool PortAllocator::SetConfiguration(
pooled_sessions_.clear(); pooled_sessions_.clear();
} }
turn_customizer_ = turn_customizer;
// If |candidate_pool_size_| is less than the number of pooled sessions, get // If |candidate_pool_size_| is less than the number of pooled sessions, get
// rid of the extras. // rid of the extras.
while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) { while (candidate_pool_size_ < static_cast<int>(pooled_sessions_.size())) {

View File

@ -25,6 +25,7 @@
namespace webrtc { namespace webrtc {
class MetricsObserverInterface; class MetricsObserverInterface;
class TurnCustomizer;
} }
namespace cricket { namespace cricket {
@ -362,7 +363,8 @@ class PortAllocator : public sigslot::has_slots<> {
bool SetConfiguration(const ServerAddresses& stun_servers, bool SetConfiguration(const ServerAddresses& stun_servers,
const std::vector<RelayServerConfig>& turn_servers, const std::vector<RelayServerConfig>& turn_servers,
int candidate_pool_size, int candidate_pool_size,
bool prune_turn_ports); bool prune_turn_ports,
webrtc::TurnCustomizer* turn_customizer = nullptr);
const ServerAddresses& stun_servers() const { return stun_servers_; } const ServerAddresses& stun_servers() const { return stun_servers_; }
@ -477,6 +479,10 @@ class PortAllocator : public sigslot::has_slots<> {
metrics_observer_ = observer; metrics_observer_ = observer;
} }
webrtc::TurnCustomizer* turn_customizer() {
return turn_customizer_;
}
protected: protected:
virtual PortAllocatorSession* CreateSessionInternal( virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name, const std::string& content_name,
@ -512,6 +518,11 @@ class PortAllocator : public sigslot::has_slots<> {
bool prune_turn_ports_ = false; bool prune_turn_ports_ = false;
webrtc::MetricsObserverInterface* metrics_observer_ = nullptr; webrtc::MetricsObserverInterface* metrics_observer_ = nullptr;
// Customizer for TURN messages.
// The instance is owned by application and will be shared among
// all TurnPort(s) created.
webrtc::TurnCustomizer* turn_customizer_ = nullptr;
}; };
} // namespace cricket } // namespace cricket

View File

@ -67,9 +67,18 @@ bool StunMessage::SetTransactionID(const std::string& str) {
return true; return true;
} }
static bool ImplementationDefinedRange(int attr_type)
{
return attr_type >= 0xC000 && attr_type <= 0xFFFF;
}
void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) { void StunMessage::AddAttribute(std::unique_ptr<StunAttribute> attr) {
// Fail any attributes that aren't valid for this type of message. // Fail any attributes that aren't valid for this type of message,
// but allow any type for the range that is "implementation defined"
// in the RFC.
if (!ImplementationDefinedRange(attr->type())) {
RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type())); RTC_DCHECK_EQ(attr->value_type(), GetAttributeValueType(attr->type()));
}
attr->SetOwner(this); attr->SetOwner(this);
size_t attr_length = attr->length(); size_t attr_length = attr->length();
@ -398,8 +407,16 @@ StunAttributeValueType StunMessage::GetAttributeValueType(int type) const {
StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ { StunAttribute* StunMessage::CreateAttribute(int type, size_t length) /*const*/ {
StunAttributeValueType value_type = GetAttributeValueType(type); StunAttributeValueType value_type = GetAttributeValueType(type);
return StunAttribute::Create(value_type, type, static_cast<uint16_t>(length), if (value_type != STUN_VALUE_UNKNOWN) {
this); return StunAttribute::Create(value_type, type,
static_cast<uint16_t>(length), this);
} else if (ImplementationDefinedRange(type)) {
// Read unknown attributes as STUN_VALUE_BYTE_STRING
return StunAttribute::Create(STUN_VALUE_BYTE_STRING, type,
static_cast<uint16_t>(length), this);
} else {
return NULL;
}
} }
const StunAttribute* StunMessage::GetAttribute(int type) const { const StunAttribute* StunMessage::GetAttribute(int type) const {

View File

@ -207,6 +207,10 @@ const StunMessage* StunRequest::msg() const {
return msg_; return msg_;
} }
StunMessage* StunRequest::mutable_msg() {
return msg_;
}
int StunRequest::Elapsed() const { int StunRequest::Elapsed() const {
return static_cast<int>(rtc::TimeMillis() - tstamp_); return static_cast<int>(rtc::TimeMillis() - tstamp_);
} }

View File

@ -105,6 +105,9 @@ class StunRequest : public rtc::MessageHandler {
// Returns a const pointer to |msg_|. // Returns a const pointer to |msg_|.
const StunMessage* msg() const; const StunMessage* msg() const;
// Returns a mutable pointer to |msg_|.
StunMessage* mutable_msg();
// Time elapsed since last send (in ms) // Time elapsed since last send (in ms)
int Elapsed() const; int Elapsed() const;

View File

@ -0,0 +1,57 @@
/*
* Copyright 2017 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef P2P_BASE_TESTTURNCUSTOMIZER_H_
#define P2P_BASE_TESTTURNCUSTOMIZER_H_
#include "api/turncustomizer.h"
#include "rtc_base/ptr_util.h"
namespace cricket {
class TestTurnCustomizer : public webrtc::TurnCustomizer {
public:
TestTurnCustomizer() {}
virtual ~TestTurnCustomizer() {}
enum TestTurnAttributeExtensions {
// Test only attribute
STUN_ATTR_COUNTER = 0xFF02 // Number
};
void MaybeModifyOutgoingStunMessage(
cricket::PortInterface* port,
cricket::StunMessage* message) override {
modify_cnt_ ++;
if (add_counter_) {
message->AddAttribute(rtc::MakeUnique<cricket::StunUInt32Attribute>(
STUN_ATTR_COUNTER, modify_cnt_));
}
return;
}
bool AllowChannelData(cricket::PortInterface* port,
const void* data,
size_t size,
bool payload) override {
allow_channel_data_cnt_++;
return allow_channel_data_;
}
bool add_counter_ = false;
bool allow_channel_data_ = true;
unsigned int modify_cnt_ = 0;
unsigned int allow_channel_data_cnt_ = 0;
};
} // namespace cricket
#endif // P2P_BASE_TESTTURNCUSTOMIZER_H_

View File

@ -196,7 +196,8 @@ TurnPort::TurnPort(rtc::Thread* thread,
const ProtocolAddress& server_address, const ProtocolAddress& server_address,
const RelayCredentials& credentials, const RelayCredentials& credentials,
int server_priority, int server_priority,
const std::string& origin) const std::string& origin,
webrtc::TurnCustomizer* customizer)
: Port(thread, : Port(thread,
RELAY_PORT_TYPE, RELAY_PORT_TYPE,
factory, factory,
@ -212,7 +213,8 @@ TurnPort::TurnPort(rtc::Thread* thread,
next_channel_number_(TURN_CHANNEL_NUMBER_START), next_channel_number_(TURN_CHANNEL_NUMBER_START),
state_(STATE_CONNECTING), state_(STATE_CONNECTING),
server_priority_(server_priority), server_priority_(server_priority),
allocate_mismatch_retries_(0) { allocate_mismatch_retries_(0),
turn_customizer_(customizer) {
request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
request_manager_.set_origin(origin); request_manager_.set_origin(origin);
} }
@ -229,7 +231,8 @@ TurnPort::TurnPort(rtc::Thread* thread,
int server_priority, int server_priority,
const std::string& origin, const std::string& origin,
const std::vector<std::string>& tls_alpn_protocols, const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves) const std::vector<std::string>& tls_elliptic_curves,
webrtc::TurnCustomizer* customizer)
: Port(thread, : Port(thread,
RELAY_PORT_TYPE, RELAY_PORT_TYPE,
factory, factory,
@ -249,7 +252,8 @@ TurnPort::TurnPort(rtc::Thread* thread,
next_channel_number_(TURN_CHANNEL_NUMBER_START), next_channel_number_(TURN_CHANNEL_NUMBER_START),
state_(STATE_CONNECTING), state_(STATE_CONNECTING),
server_priority_(server_priority), server_priority_(server_priority),
allocate_mismatch_retries_(0) { allocate_mismatch_retries_(0),
turn_customizer_(customizer) {
request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
request_manager_.set_origin(origin); request_manager_.set_origin(origin);
} }
@ -952,6 +956,7 @@ bool TurnPort::ScheduleRefresh(int lifetime) {
} }
void TurnPort::SendRequest(StunRequest* req, int delay) { void TurnPort::SendRequest(StunRequest* req, int delay) {
TurnCustomizerMaybeModifyOutgoingStunMessage(req->mutable_msg());
request_manager_.SendDelayed(req, delay); request_manager_.SendDelayed(req, delay);
} }
@ -1142,6 +1147,24 @@ std::string TurnPort::ReconstructedServerUrl() {
return url.str(); return url.str();
} }
void TurnPort::TurnCustomizerMaybeModifyOutgoingStunMessage(
StunMessage* message) {
if (turn_customizer_ == nullptr) {
return;
}
turn_customizer_->MaybeModifyOutgoingStunMessage(this, message);
}
bool TurnPort::TurnCustomizerAllowChannelData(
const void* data, size_t size, bool payload) {
if (turn_customizer_ == nullptr) {
return true;
}
return turn_customizer_->AllowChannelData(this, data, size, payload);
}
TurnAllocateRequest::TurnAllocateRequest(TurnPort* port) TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
: StunRequest(new TurnMessage()), : StunRequest(new TurnMessage()),
port_(port) { port_(port) {
@ -1533,8 +1556,10 @@ void TurnEntry::SendChannelBindRequest(int delay) {
int TurnEntry::Send(const void* data, size_t size, bool payload, int TurnEntry::Send(const void* data, size_t size, bool payload,
const rtc::PacketOptions& options) { const rtc::PacketOptions& options) {
rtc::ByteBufferWriter buf; rtc::ByteBufferWriter buf;
if (state_ != STATE_BOUND) { if (state_ != STATE_BOUND ||
!port_->TurnCustomizerAllowChannelData(data, size, payload)) {
// If we haven't bound the channel yet, we have to use a Send Indication. // If we haven't bound the channel yet, we have to use a Send Indication.
// The turn_customizer_ can also make us use Send Indication.
TurnMessage msg; TurnMessage msg;
msg.SetType(TURN_SEND_INDICATION); msg.SetType(TURN_SEND_INDICATION);
msg.SetTransactionID( msg.SetTransactionID(
@ -1543,6 +1568,9 @@ int TurnEntry::Send(const void* data, size_t size, bool payload,
STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_)); STUN_ATTR_XOR_PEER_ADDRESS, ext_addr_));
msg.AddAttribute( msg.AddAttribute(
rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_DATA, data, size)); rtc::MakeUnique<StunByteStringAttribute>(STUN_ATTR_DATA, data, size));
port_->TurnCustomizerMaybeModifyOutgoingStunMessage(&msg);
const bool success = msg.Write(&buf); const bool success = msg.Write(&buf);
RTC_DCHECK(success); RTC_DCHECK(success);

View File

@ -26,6 +26,10 @@ class AsyncResolver;
class SignalThread; class SignalThread;
} }
namespace webrtc {
class TurnCustomizer;
}
namespace cricket { namespace cricket {
extern const char TURN_PORT_TYPE[]; extern const char TURN_PORT_TYPE[];
@ -52,9 +56,11 @@ class TurnPort : public Port {
const ProtocolAddress& server_address, const ProtocolAddress& server_address,
const RelayCredentials& credentials, const RelayCredentials& credentials,
int server_priority, int server_priority,
const std::string& origin) { const std::string& origin,
webrtc::TurnCustomizer* customizer) {
return new TurnPort(thread, factory, network, socket, username, password, return new TurnPort(thread, factory, network, socket, username, password,
server_address, credentials, server_priority, origin); server_address, credentials, server_priority, origin,
customizer);
} }
// Create a TURN port that will use a new socket, bound to |network| and // Create a TURN port that will use a new socket, bound to |network| and
@ -71,10 +77,12 @@ class TurnPort : public Port {
int server_priority, int server_priority,
const std::string& origin, const std::string& origin,
const std::vector<std::string>& tls_alpn_protocols, const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves) { const std::vector<std::string>& tls_elliptic_curves,
webrtc::TurnCustomizer* customizer) {
return new TurnPort(thread, factory, network, min_port, max_port, username, return new TurnPort(thread, factory, network, min_port, max_port, username,
password, server_address, credentials, server_priority, password, server_address, credentials, server_priority,
origin, tls_alpn_protocols, tls_elliptic_curves); origin, tls_alpn_protocols, tls_elliptic_curves,
customizer);
} }
virtual ~TurnPort(); virtual ~TurnPort();
@ -184,7 +192,8 @@ class TurnPort : public Port {
const ProtocolAddress& server_address, const ProtocolAddress& server_address,
const RelayCredentials& credentials, const RelayCredentials& credentials,
int server_priority, int server_priority,
const std::string& origin); const std::string& origin,
webrtc::TurnCustomizer* customizer);
TurnPort(rtc::Thread* thread, TurnPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory, rtc::PacketSocketFactory* factory,
@ -198,7 +207,8 @@ class TurnPort : public Port {
int server_priority, int server_priority,
const std::string& origin, const std::string& origin,
const std::vector<std::string>& tls_alpn_protocols, const std::vector<std::string>& tls_alpn_protocols,
const std::vector<std::string>& tls_elliptic_curves); const std::vector<std::string>& tls_elliptic_curves,
webrtc::TurnCustomizer* customizer);
private: private:
enum { enum {
@ -275,6 +285,10 @@ class TurnPort : public Port {
// Reconstruct the URL of the server which the candidate is gathered from. // Reconstruct the URL of the server which the candidate is gathered from.
std::string ReconstructedServerUrl(); std::string ReconstructedServerUrl();
void TurnCustomizerMaybeModifyOutgoingStunMessage(StunMessage* message);
bool TurnCustomizerAllowChannelData(const void* data,
size_t size, bool payload);
ProtocolAddress server_address_; ProtocolAddress server_address_;
TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE; TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE;
std::vector<std::string> tls_alpn_protocols_; std::vector<std::string> tls_alpn_protocols_;
@ -305,6 +319,9 @@ class TurnPort : public Port {
rtc::AsyncInvoker invoker_; rtc::AsyncInvoker invoker_;
// Optional TurnCustomizer that can modify outgoing messages.
webrtc::TurnCustomizer *turn_customizer_ = nullptr;
friend class TurnEntry; friend class TurnEntry;
friend class TurnAllocateRequest; friend class TurnAllocateRequest;
friend class TurnRefreshRequest; friend class TurnRefreshRequest;

View File

@ -18,6 +18,7 @@
#include "p2p/base/p2pconstants.h" #include "p2p/base/p2pconstants.h"
#include "p2p/base/portallocator.h" #include "p2p/base/portallocator.h"
#include "p2p/base/tcpport.h" #include "p2p/base/tcpport.h"
#include "p2p/base/testturncustomizer.h"
#include "p2p/base/testturnserver.h" #include "p2p/base/testturnserver.h"
#include "p2p/base/turnport.h" #include "p2p/base/turnport.h"
#include "p2p/base/udpport.h" #include "p2p/base/udpport.h"
@ -30,6 +31,7 @@
#include "rtc_base/gunit.h" #include "rtc_base/gunit.h"
#include "rtc_base/helpers.h" #include "rtc_base/helpers.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/socketadapters.h" #include "rtc_base/socketadapters.h"
#include "rtc_base/socketaddress.h" #include "rtc_base/socketaddress.h"
#include "rtc_base/ssladapter.h" #include "rtc_base/ssladapter.h"
@ -264,7 +266,7 @@ class TurnPortTest : public testing::Test,
turn_port_.reset(TurnPort::Create( turn_port_.reset(TurnPort::Create(
&main_, &socket_factory_, network, 0, 0, kIceUfrag1, kIcePwd1, &main_, &socket_factory_, network, 0, 0, kIceUfrag1, kIcePwd1,
server_address, credentials, 0, origin, std::vector<std::string>(), server_address, credentials, 0, origin, std::vector<std::string>(),
std::vector<std::string>())); std::vector<std::string>(), turn_customizer_.get()));
// This TURN port will be the controlling. // This TURN port will be the controlling.
turn_port_->SetIceRole(ICEROLE_CONTROLLING); turn_port_->SetIceRole(ICEROLE_CONTROLLING);
ConnectSignals(); ConnectSignals();
@ -294,7 +296,8 @@ class TurnPortTest : public testing::Test,
RelayCredentials credentials(username, password); RelayCredentials credentials(username, password);
turn_port_.reset(TurnPort::Create( turn_port_.reset(TurnPort::Create(
&main_, &socket_factory_, MakeNetwork(kLocalAddr1), socket_.get(), &main_, &socket_factory_, MakeNetwork(kLocalAddr1), socket_.get(),
kIceUfrag1, kIcePwd1, server_address, credentials, 0, std::string())); kIceUfrag1, kIcePwd1, server_address, credentials, 0, std::string(),
nullptr));
// This TURN port will be the controlling. // This TURN port will be the controlling.
turn_port_->SetIceRole(ICEROLE_CONTROLLING); turn_port_->SetIceRole(ICEROLE_CONTROLLING);
ConnectSignals(); ConnectSignals();
@ -695,6 +698,7 @@ class TurnPortTest : public testing::Test,
std::vector<rtc::Buffer> turn_packets_; std::vector<rtc::Buffer> turn_packets_;
std::vector<rtc::Buffer> udp_packets_; std::vector<rtc::Buffer> udp_packets_;
rtc::PacketOptions options; rtc::PacketOptions options;
std::unique_ptr<webrtc::TurnCustomizer> turn_customizer_;
}; };
TEST_F(TurnPortTest, TestTurnPortType) { TEST_F(TurnPortTest, TestTurnPortType) {
@ -1458,4 +1462,146 @@ TEST_F(TurnPortTest, TestResolverShutdown) {
} }
#endif #endif
class MessageObserver : public StunMessageObserver{
public:
MessageObserver(unsigned int *message_counter,
unsigned int* channel_data_counter,
unsigned int *attr_counter)
: message_counter_(message_counter),
channel_data_counter_(channel_data_counter),
attr_counter_(attr_counter) {}
virtual ~MessageObserver() {}
virtual void ReceivedMessage(const TurnMessage* msg) override {
if (message_counter_ != nullptr) {
(*message_counter_)++;
}
// Implementation defined attributes are returned as ByteString
const StunByteStringAttribute* attr = msg->GetByteString(
TestTurnCustomizer::STUN_ATTR_COUNTER);
if (attr != nullptr && attr_counter_ != nullptr) {
rtc::ByteBufferReader buf(attr->bytes(), attr->length());
unsigned int val = ~0u;
buf.ReadUInt32(&val);
(*attr_counter_)++;
}
}
virtual void ReceivedChannelData(const char* data, size_t size) override {
if (channel_data_counter_ != nullptr) {
(*channel_data_counter_)++;
}
}
// Number of TurnMessages observed.
unsigned int* message_counter_ = nullptr;
// Number of channel data observed.
unsigned int* channel_data_counter_ = nullptr;
// Number of TurnMessages that had STUN_ATTR_COUNTER.
unsigned int* attr_counter_ = nullptr;
};
// Do a TURN allocation, establish a TLS connection, and send some data.
// Add customizer and check that it get called.
TEST_F(TurnPortTest, TestTurnCustomizerCount) {
unsigned int observer_message_counter = 0;
unsigned int observer_channel_data_counter = 0;
unsigned int observer_attr_counter = 0;
TestTurnCustomizer* customizer = new TestTurnCustomizer();
std::unique_ptr<MessageObserver> validator(new MessageObserver(
&observer_message_counter,
&observer_channel_data_counter,
&observer_attr_counter));
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS);
turn_customizer_.reset(customizer);
turn_server_.server()->SetStunMessageObserver(std::move(validator));
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr);
TestTurnSendData(PROTO_TLS);
EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol());
// There should have been at least turn_packets_.size() calls to |customizer|.
EXPECT_GE(customizer->modify_cnt_ + customizer->allow_channel_data_cnt_,
turn_packets_.size());
// Some channel data should be received.
EXPECT_GE(observer_channel_data_counter, 0u);
// Need to release TURN port before the customizer.
turn_port_.reset(nullptr);
}
// Do a TURN allocation, establish a TLS connection, and send some data.
// Add customizer and check that it can can prevent usage of channel data.
TEST_F(TurnPortTest, TestTurnCustomizerDisallowChannelData) {
unsigned int observer_message_counter = 0;
unsigned int observer_channel_data_counter = 0;
unsigned int observer_attr_counter = 0;
TestTurnCustomizer* customizer = new TestTurnCustomizer();
std::unique_ptr<MessageObserver> validator(new MessageObserver(
&observer_message_counter,
&observer_channel_data_counter,
&observer_attr_counter));
customizer->allow_channel_data_ = false;
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS);
turn_customizer_.reset(customizer);
turn_server_.server()->SetStunMessageObserver(std::move(validator));
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr);
TestTurnSendData(PROTO_TLS);
EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol());
// There should have been at least turn_packets_.size() calls to |customizer|.
EXPECT_GE(customizer->modify_cnt_, turn_packets_.size());
// No channel data should be received.
EXPECT_EQ(observer_channel_data_counter, 0u);
// Need to release TURN port before the customizer.
turn_port_.reset(nullptr);
}
// Do a TURN allocation, establish a TLS connection, and send some data.
// Add customizer and check that it can add attribute to messages.
TEST_F(TurnPortTest, TestTurnCustomizerAddAttribute) {
unsigned int observer_message_counter = 0;
unsigned int observer_channel_data_counter = 0;
unsigned int observer_attr_counter = 0;
TestTurnCustomizer* customizer = new TestTurnCustomizer();
std::unique_ptr<MessageObserver> validator(new MessageObserver(
&observer_message_counter,
&observer_channel_data_counter,
&observer_attr_counter));
customizer->allow_channel_data_ = false;
customizer->add_counter_ = true;
turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TLS);
turn_customizer_.reset(customizer);
turn_server_.server()->SetStunMessageObserver(std::move(validator));
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTlsProtoAddr);
TestTurnSendData(PROTO_TLS);
EXPECT_EQ(TLS_PROTOCOL_NAME, turn_port_->Candidates()[0].relay_protocol());
// There should have been at least turn_packets_.size() calls to |customizer|.
EXPECT_GE(customizer->modify_cnt_, turn_packets_.size());
// Everything will be sent as messages since channel data is disallowed.
EXPECT_GE(customizer->modify_cnt_, observer_message_counter);
// All messages should have attribute.
EXPECT_EQ(observer_message_counter, observer_attr_counter);
// At least allow_channel_data_cnt_ messages should have been sent.
EXPECT_GE(customizer->modify_cnt_, customizer->allow_channel_data_cnt_);
EXPECT_GE(customizer->allow_channel_data_cnt_, 0u);
// No channel data should be received.
EXPECT_EQ(observer_channel_data_counter, 0u);
// Need to release TURN port before the customizer.
turn_port_.reset(nullptr);
}
} // namespace cricket } // namespace cricket

View File

@ -211,6 +211,9 @@ void TurnServer::OnInternalPacket(rtc::AsyncPacketSocket* socket,
if (allocation) { if (allocation) {
allocation->HandleChannelData(data, size); allocation->HandleChannelData(data, size);
} }
if (stun_message_observer_ != nullptr) {
stun_message_observer_->ReceivedChannelData(data, size);
}
} }
} }
@ -223,6 +226,10 @@ void TurnServer::HandleStunMessage(TurnServerConnection* conn, const char* data,
return; return;
} }
if (stun_message_observer_ != nullptr) {
stun_message_observer_->ReceivedMessage(&msg);
}
// If it's a STUN binding request, handle that specially. // If it's a STUN binding request, handle that specially.
if (msg.type() == STUN_BINDING_REQUEST) { if (msg.type() == STUN_BINDING_REQUEST) {
HandleBindingRequest(conn, &msg); HandleBindingRequest(conn, &msg);

View File

@ -157,6 +157,13 @@ class TurnRedirectInterface {
virtual ~TurnRedirectInterface() {} virtual ~TurnRedirectInterface() {}
}; };
class StunMessageObserver {
public:
virtual void ReceivedMessage(const TurnMessage* msg) = 0;
virtual void ReceivedChannelData(const char* data, size_t size) = 0;
virtual ~StunMessageObserver() {}
};
// The core TURN server class. Give it a socket to listen on via // The core TURN server class. Give it a socket to listen on via
// AddInternalServerSocket, and a factory to create external sockets via // AddInternalServerSocket, and a factory to create external sockets via
// SetExternalSocketFactory, and it's ready to go. // SetExternalSocketFactory, and it's ready to go.
@ -214,6 +221,11 @@ class TurnServer : public sigslot::has_slots<> {
return GenerateNonce(timestamp); return GenerateNonce(timestamp);
} }
void SetStunMessageObserver(
std::unique_ptr<StunMessageObserver> observer) {
stun_message_observer_ = std::move(observer);
}
private: private:
std::string GenerateNonce(int64_t now) const; std::string GenerateNonce(int64_t now) const;
void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data, void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data,
@ -296,6 +308,9 @@ class TurnServer : public sigslot::has_slots<> {
// from this value, and it will be reset to 0 after generating the NONCE. // from this value, and it will be reset to 0 after generating the NONCE.
int64_t ts_for_next_nonce_ = 0; int64_t ts_for_next_nonce_ = 0;
// For testing only. Used to observe STUN messages received.
std::unique_ptr<StunMessageObserver> stun_message_observer_;
friend class TurnServerAllocation; friend class TurnServerAllocation;
}; };

View File

@ -96,11 +96,15 @@ const uint32_t DISABLE_ALL_PHASES =
PORTALLOCATOR_DISABLE_STUN | PORTALLOCATOR_DISABLE_RELAY; PORTALLOCATOR_DISABLE_STUN | PORTALLOCATOR_DISABLE_RELAY;
// BasicPortAllocator // BasicPortAllocator
BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager, BasicPortAllocator::BasicPortAllocator(
rtc::PacketSocketFactory* socket_factory) rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory,
webrtc::TurnCustomizer* customizer)
: network_manager_(network_manager), socket_factory_(socket_factory) { : network_manager_(network_manager), socket_factory_(socket_factory) {
RTC_DCHECK(network_manager_ != nullptr); RTC_DCHECK(network_manager_ != nullptr);
RTC_DCHECK(socket_factory_ != nullptr); RTC_DCHECK(socket_factory_ != nullptr);
SetConfiguration(ServerAddresses(), std::vector<RelayServerConfig>(),
0, false, customizer);
Construct(); Construct();
} }
@ -115,7 +119,8 @@ BasicPortAllocator::BasicPortAllocator(rtc::NetworkManager* network_manager,
const ServerAddresses& stun_servers) const ServerAddresses& stun_servers)
: network_manager_(network_manager), socket_factory_(socket_factory) { : network_manager_(network_manager), socket_factory_(socket_factory) {
RTC_DCHECK(socket_factory_ != NULL); RTC_DCHECK(socket_factory_ != NULL);
SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false); SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false,
nullptr);
Construct(); Construct();
} }
@ -142,7 +147,7 @@ BasicPortAllocator::BasicPortAllocator(
turn_servers.push_back(config); turn_servers.push_back(config);
} }
SetConfiguration(stun_servers, turn_servers, 0, false); SetConfiguration(stun_servers, turn_servers, 0, false, nullptr);
Construct(); Construct();
} }
@ -188,7 +193,7 @@ void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) {
std::vector<RelayServerConfig> new_turn_servers = turn_servers(); std::vector<RelayServerConfig> new_turn_servers = turn_servers();
new_turn_servers.push_back(turn_server); new_turn_servers.push_back(turn_server);
SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size(), SetConfiguration(stun_servers(), new_turn_servers, candidate_pool_size(),
prune_turn_ports()); prune_turn_ports(), turn_customizer());
} }
// BasicPortAllocatorSession // BasicPortAllocatorSession
@ -1374,7 +1379,6 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
continue; continue;
} }
// Shared socket mode must be enabled only for UDP based ports. Hence // Shared socket mode must be enabled only for UDP based ports. Hence
// don't pass shared socket for ports which will create TCP sockets. // don't pass shared socket for ports which will create TCP sockets.
// TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
@ -1386,7 +1390,8 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
network_, udp_socket_.get(), network_, udp_socket_.get(),
session_->username(), session_->password(), session_->username(), session_->password(),
*relay_port, config.credentials, config.priority, *relay_port, config.credentials, config.priority,
session_->allocator()->origin()); session_->allocator()->origin(),
session_->allocator()->turn_customizer());
turn_ports_.push_back(port); turn_ports_.push_back(port);
// Listen to the port destroyed signal, to allow AllocationSequence to // Listen to the port destroyed signal, to allow AllocationSequence to
// remove entrt from it's map. // remove entrt from it's map.
@ -1397,7 +1402,8 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
session_->allocator()->min_port(), session_->allocator()->max_port(), session_->allocator()->min_port(), session_->allocator()->max_port(),
session_->username(), session_->password(), *relay_port, session_->username(), session_->password(), *relay_port,
config.credentials, config.priority, session_->allocator()->origin(), config.credentials, config.priority, session_->allocator()->origin(),
config.tls_alpn_protocols, config.tls_elliptic_curves); config.tls_alpn_protocols, config.tls_elliptic_curves,
session_->allocator()->turn_customizer());
} }
RTC_DCHECK(port != NULL); RTC_DCHECK(port != NULL);
port->SetTlsCertPolicy(config.tls_cert_policy); port->SetTlsCertPolicy(config.tls_cert_policy);

View File

@ -15,6 +15,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "api/turncustomizer.h"
#include "p2p/base/portallocator.h" #include "p2p/base/portallocator.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/messagequeue.h" #include "rtc_base/messagequeue.h"
@ -26,7 +27,8 @@ namespace cricket {
class BasicPortAllocator : public PortAllocator { class BasicPortAllocator : public PortAllocator {
public: public:
BasicPortAllocator(rtc::NetworkManager* network_manager, BasicPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory); rtc::PacketSocketFactory* socket_factory,
webrtc::TurnCustomizer* customizer = nullptr);
explicit BasicPortAllocator(rtc::NetworkManager* network_manager); explicit BasicPortAllocator(rtc::NetworkManager* network_manager);
BasicPortAllocator(rtc::NetworkManager* network_manager, BasicPortAllocator(rtc::NetworkManager* network_manager,
rtc::PacketSocketFactory* socket_factory, rtc::PacketSocketFactory* socket_factory,

View File

@ -277,6 +277,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
bool redetermine_role_on_ice_restart; bool redetermine_role_on_ice_restart;
rtc::Optional<int> ice_check_min_interval; rtc::Optional<int> ice_check_min_interval;
rtc::Optional<rtc::IntervalRange> ice_regather_interval_range; rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
webrtc::TurnCustomizer* turn_customizer;
}; };
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this), static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
"Did you add something to RTCConfiguration and forget to " "Did you add something to RTCConfiguration and forget to "
@ -312,7 +313,8 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
enable_ice_renomination == o.enable_ice_renomination && enable_ice_renomination == o.enable_ice_renomination &&
redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart && redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart &&
ice_check_min_interval == o.ice_check_min_interval && ice_check_min_interval == o.ice_check_min_interval &&
ice_regather_interval_range == o.ice_regather_interval_range; ice_regather_interval_range == o.ice_regather_interval_range &&
turn_customizer == o.turn_customizer;
} }
bool PeerConnectionInterface::RTCConfiguration::operator!=( bool PeerConnectionInterface::RTCConfiguration::operator!=(
@ -454,6 +456,7 @@ bool PeerConnection::Initialize(
<< "This shouldn't happen if using PeerConnectionFactory."; << "This shouldn't happen if using PeerConnectionFactory.";
return false; return false;
} }
if (!observer) { if (!observer) {
// TODO(deadbeef): Why do we do this? // TODO(deadbeef): Why do we do this?
LOG(LS_ERROR) << "PeerConnection initialized without a " LOG(LS_ERROR) << "PeerConnection initialized without a "
@ -1147,6 +1150,7 @@ bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration,
configuration.ice_candidate_pool_size; configuration.ice_candidate_pool_size;
modified_config.prune_turn_ports = configuration.prune_turn_ports; modified_config.prune_turn_ports = configuration.prune_turn_ports;
modified_config.ice_check_min_interval = configuration.ice_check_min_interval; modified_config.ice_check_min_interval = configuration.ice_check_min_interval;
modified_config.turn_customizer = configuration.turn_customizer;
if (configuration != modified_config) { if (configuration != modified_config) {
LOG(LS_ERROR) << "Modifying the configuration in an unsupported way."; LOG(LS_ERROR) << "Modifying the configuration in an unsupported way.";
return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error); return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
@ -1180,7 +1184,8 @@ bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration,
rtc::Bind(&PeerConnection::ReconfigurePortAllocator_n, this, rtc::Bind(&PeerConnection::ReconfigurePortAllocator_n, this,
stun_servers, turn_servers, modified_config.type, stun_servers, turn_servers, modified_config.type,
modified_config.ice_candidate_pool_size, modified_config.ice_candidate_pool_size,
modified_config.prune_turn_ports))) { modified_config.prune_turn_ports,
modified_config.turn_customizer))) {
LOG(LS_ERROR) << "Failed to apply configuration to PortAllocator."; LOG(LS_ERROR) << "Failed to apply configuration to PortAllocator.";
return SafeSetError(RTCErrorType::INTERNAL_ERROR, error); return SafeSetError(RTCErrorType::INTERNAL_ERROR, error);
} }
@ -2520,7 +2525,8 @@ bool PeerConnection::InitializePortAllocator_n(
// properties set above. // properties set above.
port_allocator_->SetConfiguration(stun_servers, turn_servers, port_allocator_->SetConfiguration(stun_servers, turn_servers,
configuration.ice_candidate_pool_size, configuration.ice_candidate_pool_size,
configuration.prune_turn_ports); configuration.prune_turn_ports,
configuration.turn_customizer);
return true; return true;
} }
@ -2529,13 +2535,15 @@ bool PeerConnection::ReconfigurePortAllocator_n(
const std::vector<cricket::RelayServerConfig>& turn_servers, const std::vector<cricket::RelayServerConfig>& turn_servers,
IceTransportsType type, IceTransportsType type,
int candidate_pool_size, int candidate_pool_size,
bool prune_turn_ports) { bool prune_turn_ports,
webrtc::TurnCustomizer* turn_customizer) {
port_allocator_->set_candidate_filter( port_allocator_->set_candidate_filter(
ConvertIceTransportTypeToCandidateFilter(type)); ConvertIceTransportTypeToCandidateFilter(type));
// Call this last since it may create pooled allocator sessions using the // Call this last since it may create pooled allocator sessions using the
// candidate filter set above. // candidate filter set above.
return port_allocator_->SetConfiguration( return port_allocator_->SetConfiguration(
stun_servers, turn_servers, candidate_pool_size, prune_turn_ports); stun_servers, turn_servers, candidate_pool_size, prune_turn_ports,
turn_customizer);
} }
bool PeerConnection::StartRtcEventLog_w(rtc::PlatformFile file, bool PeerConnection::StartRtcEventLog_w(rtc::PlatformFile file,

View File

@ -17,6 +17,7 @@
#include <vector> #include <vector>
#include "api/peerconnectioninterface.h" #include "api/peerconnectioninterface.h"
#include "api/turncustomizer.h"
#include "pc/iceserverparsing.h" #include "pc/iceserverparsing.h"
#include "pc/peerconnectionfactory.h" #include "pc/peerconnectionfactory.h"
#include "pc/rtcstatscollector.h" #include "pc/rtcstatscollector.h"
@ -437,7 +438,8 @@ class PeerConnection : public PeerConnectionInterface,
const std::vector<cricket::RelayServerConfig>& turn_servers, const std::vector<cricket::RelayServerConfig>& turn_servers,
IceTransportsType type, IceTransportsType type,
int candidate_pool_size, int candidate_pool_size,
bool prune_turn_ports); bool prune_turn_ports,
webrtc::TurnCustomizer* turn_customizer);
// Starts recording an RTC event log using the supplied platform file. // Starts recording an RTC event log using the supplied platform file.
// This function should only be called from the worker thread. // This function should only be called from the worker thread.

View File

@ -31,6 +31,7 @@
#include "p2p/base/p2pconstants.h" #include "p2p/base/p2pconstants.h"
#include "p2p/base/portinterface.h" #include "p2p/base/portinterface.h"
#include "p2p/base/sessiondescription.h" #include "p2p/base/sessiondescription.h"
#include "p2p/base/testturncustomizer.h"
#include "p2p/base/testturnserver.h" #include "p2p/base/testturnserver.h"
#include "p2p/client/basicportallocator.h" #include "p2p/client/basicportallocator.h"
#include "pc/dtmfsender.h" #include "pc/dtmfsender.h"
@ -2992,6 +2993,7 @@ TEST_F(PeerConnectionIntegrationTest, EndToEndConnectionTimeWithTurnTurnPair) {
cricket::TestTurnServer turn_server_2(network_thread(), cricket::TestTurnServer turn_server_2(network_thread(),
turn_server_2_internal_address, turn_server_2_internal_address,
turn_server_2_external_address); turn_server_2_external_address);
// Bypass permission check on received packets so media can be sent before // Bypass permission check on received packets so media can be sent before
// the candidate is signaled. // the candidate is signaled.
turn_server_1.set_enable_permission_checks(false); turn_server_1.set_enable_permission_checks(false);
@ -3038,6 +3040,71 @@ TEST_F(PeerConnectionIntegrationTest, EndToEndConnectionTimeWithTurnTurnPair) {
delete SetCalleePcWrapperAndReturnCurrent(nullptr); delete SetCalleePcWrapperAndReturnCurrent(nullptr);
} }
// Verify that a TurnCustomizer passed in through RTCConfiguration
// is actually used by the underlying TURN candidate pair.
// Note that turnport_unittest.cc contains more detailed, lower-level tests.
TEST_F(PeerConnectionIntegrationTest, \
TurnCustomizerUsedForTurnConnections) {
static const rtc::SocketAddress turn_server_1_internal_address{"88.88.88.0",
3478};
static const rtc::SocketAddress turn_server_1_external_address{"88.88.88.1",
0};
static const rtc::SocketAddress turn_server_2_internal_address{"99.99.99.0",
3478};
static const rtc::SocketAddress turn_server_2_external_address{"99.99.99.1",
0};
cricket::TestTurnServer turn_server_1(network_thread(),
turn_server_1_internal_address,
turn_server_1_external_address);
cricket::TestTurnServer turn_server_2(network_thread(),
turn_server_2_internal_address,
turn_server_2_external_address);
PeerConnectionInterface::RTCConfiguration client_1_config;
webrtc::PeerConnectionInterface::IceServer ice_server_1;
ice_server_1.urls.push_back("turn:88.88.88.0:3478");
ice_server_1.username = "test";
ice_server_1.password = "test";
client_1_config.servers.push_back(ice_server_1);
client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
auto customizer1 = rtc::MakeUnique<cricket::TestTurnCustomizer>();
client_1_config.turn_customizer = customizer1.get();
PeerConnectionInterface::RTCConfiguration client_2_config;
webrtc::PeerConnectionInterface::IceServer ice_server_2;
ice_server_2.urls.push_back("turn:99.99.99.0:3478");
ice_server_2.username = "test";
ice_server_2.password = "test";
client_2_config.servers.push_back(ice_server_2);
client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
auto customizer2 = rtc::MakeUnique<cricket::TestTurnCustomizer>();
client_2_config.turn_customizer = customizer2.get();
ASSERT_TRUE(
CreatePeerConnectionWrappersWithConfig(client_1_config, client_2_config));
ConnectFakeSignaling();
// Set "offer to receive audio/video" without adding any tracks, so we just
// set up ICE/DTLS with no media.
PeerConnectionInterface::RTCOfferAnswerOptions options;
options.offer_to_receive_audio = 1;
options.offer_to_receive_video = 1;
caller()->SetOfferAnswerOptions(options);
caller()->CreateAndSetAndSignalOffer();
ASSERT_TRUE_WAIT(DtlsConnected(), kDefaultTimeout);
EXPECT_GT(customizer1->allow_channel_data_cnt_, 0u);
EXPECT_GT(customizer1->modify_cnt_, 0u);
EXPECT_GT(customizer2->allow_channel_data_cnt_, 0u);
EXPECT_GT(customizer2->modify_cnt_, 0u);
// Need to free the clients here since they're using things we created on
// the stack.
delete SetCallerPcWrapperAndReturnCurrent(nullptr);
delete SetCalleePcWrapperAndReturnCurrent(nullptr);
}
// Test that audio and video flow end-to-end when codec names don't use the // Test that audio and video flow end-to-end when codec names don't use the
// expected casing, given that they're supposed to be case insensitive. To test // expected casing, given that they're supposed to be case insensitive. To test
// this, all but one codec is removed from each media description, and its // this, all but one codec is removed from each media description, and its

View File

@ -17,6 +17,7 @@
#include "api/mediastreamtrackproxy.h" #include "api/mediastreamtrackproxy.h"
#include "api/peerconnectionfactoryproxy.h" #include "api/peerconnectionfactoryproxy.h"
#include "api/peerconnectionproxy.h" #include "api/peerconnectionproxy.h"
#include "api/turncustomizer.h"
#include "api/videosourceproxy.h" #include "api/videosourceproxy.h"
#include "logging/rtc_event_log/rtc_event_log.h" #include "logging/rtc_event_log/rtc_event_log.h"
#include "rtc_base/bind.h" #include "rtc_base/bind.h"
@ -236,7 +237,8 @@ PeerConnectionFactory::CreatePeerConnection(
if (!allocator) { if (!allocator) {
allocator.reset(new cricket::BasicPortAllocator( allocator.reset(new cricket::BasicPortAllocator(
default_network_manager_.get(), default_socket_factory_.get())); default_network_manager_.get(), default_socket_factory_.get(),
configuration.turn_customizer));
} }
network_thread_->Invoke<void>( network_thread_->Invoke<void>(
RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::SetNetworkIgnoreMask, RTC_FROM_HERE, rtc::Bind(&cricket::PortAllocator::SetNetworkIgnoreMask,

View File

@ -249,6 +249,7 @@ rtc_static_library("peerconnection_jni") {
"src/jni/pc/sdpobserver_jni.h", "src/jni/pc/sdpobserver_jni.h",
"src/jni/pc/statsobserver_jni.cc", "src/jni/pc/statsobserver_jni.cc",
"src/jni/pc/statsobserver_jni.h", "src/jni/pc/statsobserver_jni.h",
"src/jni/pc/turncustomizer_jni.cc",
] ]
configs += [ ":libjingle_peerconnection_jni_warnings_config" ] configs += [ ":libjingle_peerconnection_jni_warnings_config" ]
@ -420,6 +421,7 @@ android_library("libjingle_peerconnection_java") {
"api/org/webrtc/StatsReport.java", "api/org/webrtc/StatsReport.java",
"api/org/webrtc/SurfaceTextureHelper.java", "api/org/webrtc/SurfaceTextureHelper.java",
"api/org/webrtc/SurfaceViewRenderer.java", "api/org/webrtc/SurfaceViewRenderer.java",
"api/org/webrtc/TurnCustomizer.java",
"api/org/webrtc/VideoCapturer.java", "api/org/webrtc/VideoCapturer.java",
"api/org/webrtc/VideoCodecInfo.java", "api/org/webrtc/VideoCodecInfo.java",
"api/org/webrtc/VideoCodecStatus.java", "api/org/webrtc/VideoCodecStatus.java",

View File

@ -304,6 +304,9 @@ public class PeerConnection {
public int maxIPv6Networks; public int maxIPv6Networks;
public IntervalRange iceRegatherIntervalRange; public IntervalRange iceRegatherIntervalRange;
// This is an optional wrapper for the C++ webrtc::TurnCustomizer.
public TurnCustomizer turnCustomizer;
// TODO(deadbeef): Instead of duplicating the defaults here, we should do // TODO(deadbeef): Instead of duplicating the defaults here, we should do
// something to pick up the defaults from C++. The Objective-C equivalent // something to pick up the defaults from C++. The Objective-C equivalent
// of RTCConfiguration does that. // of RTCConfiguration does that.

View File

@ -0,0 +1,27 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
/** Java wrapper for a C++ TurnCustomizer. */
public class TurnCustomizer {
final long nativeTurnCustomizer;
public TurnCustomizer(long nativeTurnCustomizer) {
this.nativeTurnCustomizer = nativeTurnCustomizer;
}
public void dispose() {
nativeFreeTurnCustomizer(nativeTurnCustomizer);
}
private static native void nativeFreeTurnCustomizer(
long nativeTurnCustomizer);
}

View File

@ -478,6 +478,15 @@ void JavaToNativeRTCConfiguration(
jmethodID get_max_id = jmethodID get_max_id =
GetMethodID(jni, j_interval_range_class, "getMax", "()I"); GetMethodID(jni, j_interval_range_class, "getMax", "()I");
jfieldID j_turn_customizer_type_id = GetFieldID(
jni, j_rtc_config_class, "turnCustomizer", "Lorg/webrtc/TurnCustomizer;");
jobject j_turn_customizer =
GetNullableObjectField(jni, j_rtc_config, j_turn_customizer_type_id);
jclass j_turn_customizer_class = jni->FindClass("org/webrtc/TurnCustomizer");
jfieldID j_native_turn_customizer_id =
GetFieldID(jni, j_turn_customizer_class, "nativeTurnCustomizer", "J");
rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type); rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type);
rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy); rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy);
rtc_config->rtcp_mux_policy = rtc_config->rtcp_mux_policy =
@ -522,6 +531,11 @@ void JavaToNativeRTCConfiguration(
int max = jni->CallIntMethod(j_ice_regather_interval_range, get_max_id); int max = jni->CallIntMethod(j_ice_regather_interval_range, get_max_id);
rtc_config->ice_regather_interval_range.emplace(min, max); rtc_config->ice_regather_interval_range.emplace(min, max);
} }
if (!IsNull(jni, j_turn_customizer)) {
rtc_config->turn_customizer = reinterpret_cast<webrtc::TurnCustomizer*>(
GetLongField(jni, j_turn_customizer, j_native_turn_customizer_id));
}
} }
void JavaToNativeRtpParameters(JNIEnv* jni, void JavaToNativeRtpParameters(JNIEnv* jni,

View File

@ -0,0 +1,26 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/turncustomizer.h"
#include "sdk/android/src/jni/jni_helpers.h"
namespace webrtc {
namespace jni {
JNI_FUNCTION_DECLARATION(void,
TurnCustomizer_nativeFreeTurnCustomizer,
JNIEnv* jni,
jclass,
jlong j_turn_customizer_pointer) {
delete reinterpret_cast<TurnCustomizer*>(j_turn_customizer_pointer);
}
} // namespace jni
} // namespace webrtc