Update talk to 56619788

R=wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/3839005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5120 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
sergeyu@chromium.org 2013-11-13 22:48:52 +00:00
parent e8722856f9
commit a23f0ca4ba
43 changed files with 600 additions and 236 deletions

View File

@ -248,7 +248,9 @@ void DataChannel::OnDataEngineClose() {
void DataChannel::OnDataReceived(cricket::DataChannel* channel,
const cricket::ReceiveDataParams& params,
const talk_base::Buffer& payload) {
if (params.ssrc != receive_ssrc_) {
uint32 expected_ssrc =
(data_channel_type_ == cricket::DCT_RTP) ? receive_ssrc_ : config_.id;
if (params.ssrc != expected_ssrc) {
return;
}
@ -307,7 +309,6 @@ void DataChannel::UpdateState() {
if (send_ssrc_set_ == receive_ssrc_set_) {
if (data_channel_type_ == cricket::DCT_RTP && !connected_to_provider_) {
connected_to_provider_ = provider_->ConnectDataChannel(this);
provider_->AddRtpDataStream(send_ssrc_, receive_ssrc_);
}
if (was_ever_writable_) {
// TODO(jiayl): Do not transition to kOpen if we failed to send the
@ -351,9 +352,7 @@ void DataChannel::DisconnectFromTransport() {
provider_->DisconnectDataChannel(this);
connected_to_provider_ = false;
if (data_channel_type_ == cricket::DCT_RTP) {
provider_->RemoveRtpDataStream(send_ssrc_, receive_ssrc_);
} else {
if (data_channel_type_ == cricket::DCT_SCTP) {
provider_->RemoveSctpDataStream(config_.id);
}
}
@ -429,11 +428,13 @@ bool DataChannel::InternalSendWithoutQueueing(
const DataBuffer& buffer, cricket::SendDataResult* send_result) {
cricket::SendDataParams send_params;
send_params.ssrc = send_ssrc_;
if (data_channel_type_ == cricket::DCT_SCTP) {
send_params.ordered = config_.ordered;
send_params.max_rtx_count = config_.maxRetransmits;
send_params.max_rtx_ms = config_.maxRetransmitTime;
send_params.ssrc = config_.id;
} else {
send_params.ssrc = send_ssrc_;
}
send_params.type = buffer.binary ? cricket::DMT_BINARY : cricket::DMT_TEXT;

View File

@ -53,12 +53,8 @@ class DataChannelProviderInterface {
virtual bool ConnectDataChannel(DataChannel* data_channel) = 0;
// Disconnects from the transport signals.
virtual void DisconnectDataChannel(DataChannel* data_channel) = 0;
// Adds the send and receive stream ssrc to the transport for RTP.
virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) = 0;
// Adds the data channel SID to the transport for SCTP.
virtual void AddSctpDataStream(uint32 sid) = 0;
// Removes the data channel ssrcs from the transport for RTP.
virtual void RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) = 0;
// Removes the data channel SID from the transport for SCTP.
virtual void RemoveSctpDataStream(uint32 sid) = 0;
// Returns true if the transport channel is ready to send data.
@ -149,6 +145,10 @@ class DataChannel : public DataChannelInterface,
// underlying data engine.
void SetReceiveSsrc(uint32 receive_ssrc);
cricket::DataChannelType data_channel_type() const {
return data_channel_type_;
}
protected:
DataChannel(DataChannelProviderInterface* client,
cricket::DataChannelType dct,

View File

@ -28,9 +28,16 @@
#include "talk/app/webrtc/datachannel.h"
#include "talk/app/webrtc/test/fakedatachannelprovider.h"
#include "talk/base/gunit.h"
#include "testing/base/public/gmock.h"
using webrtc::DataChannel;
class FakeDataChannelObserver : public webrtc::DataChannelObserver {
public:
MOCK_METHOD0(OnStateChange, void());
MOCK_METHOD1(OnMessage, void(const webrtc::DataBuffer& buffer));
};
class SctpDataChannelTest : public testing::Test {
protected:
SctpDataChannelTest()
@ -47,8 +54,14 @@ class SctpDataChannelTest : public testing::Test {
provider_.set_ready_to_send(true);
}
void AddObserver() {
observer_.reset(new FakeDataChannelObserver());
webrtc_data_channel_->RegisterObserver(observer_.get());
}
webrtc::DataChannelInit init_;
FakeDataChannelProvider provider_;
talk_base::scoped_ptr<FakeDataChannelObserver> observer_;
talk_base::scoped_refptr<DataChannel> webrtc_data_channel_;
};
@ -148,3 +161,41 @@ TEST_F(SctpDataChannelTest, LateCreatedChannelTransitionToOpen) {
EXPECT_TRUE_WAIT(webrtc::DataChannelInterface::kOpen == dc->state(),
1000);
}
// Tests that messages are sent with the right ssrc.
TEST_F(SctpDataChannelTest, SendDataSsrc) {
webrtc_data_channel_->SetSctpSid(1);
SetChannelReady();
webrtc::DataBuffer buffer("data");
EXPECT_TRUE(webrtc_data_channel_->Send(buffer));
EXPECT_EQ(1U, provider_.last_send_data_params().ssrc);
}
// Tests that the incoming messages with wrong ssrcs are rejected.
TEST_F(SctpDataChannelTest, ReceiveDataWithInvalidSsrc) {
webrtc_data_channel_->SetSctpSid(1);
SetChannelReady();
AddObserver();
EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(0);
cricket::ReceiveDataParams params;
params.ssrc = 0;
webrtc::DataBuffer buffer("abcd");
webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
}
// Tests that the incoming messages with right ssrcs are acceted.
TEST_F(SctpDataChannelTest, ReceiveDataWithValidSsrc) {
webrtc_data_channel_->SetSctpSid(1);
SetChannelReady();
AddObserver();
EXPECT_CALL(*(observer_.get()), OnMessage(testing::_)).Times(1);
cricket::ReceiveDataParams params;
params.ssrc = 1;
webrtc::DataBuffer buffer("abcd");
webrtc_data_channel_->OnDataReceived(NULL, params, buffer.data);
}

View File

@ -208,10 +208,10 @@ void MediaStreamSignaling::TearDown() {
bool MediaStreamSignaling::IsSctpSidAvailable(int sid) const {
if (sid < 0 || sid > static_cast<int>(cricket::kMaxSctpSid))
return false;
for (DataChannels::const_iterator iter = data_channels_.begin();
iter != data_channels_.end();
for (SctpDataChannels::const_iterator iter = sctp_data_channels_.begin();
iter != sctp_data_channels_.end();
++iter) {
if (iter->second->id() == sid) {
if ((*iter)->id() == sid) {
return false;
}
}
@ -240,17 +240,23 @@ bool MediaStreamSignaling::AllocateSctpSid(talk_base::SSLRole role, int* sid) {
}
bool MediaStreamSignaling::HasDataChannels() const {
return !data_channels_.empty();
return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
}
bool MediaStreamSignaling::AddDataChannel(DataChannel* data_channel) {
ASSERT(data_channel != NULL);
if (data_channels_.find(data_channel->label()) != data_channels_.end()) {
LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
<< " already exists.";
return false;
if (data_channel->data_channel_type() == cricket::DCT_RTP) {
if (rtp_data_channels_.find(data_channel->label()) !=
rtp_data_channels_.end()) {
LOG(LS_ERROR) << "DataChannel with label " << data_channel->label()
<< " already exists.";
return false;
}
rtp_data_channels_[data_channel->label()] = data_channel;
} else {
ASSERT(data_channel->data_channel_type() == cricket::DCT_SCTP);
sctp_data_channels_.push_back(data_channel);
}
data_channels_[data_channel->label()] = data_channel;
return true;
}
@ -262,19 +268,13 @@ bool MediaStreamSignaling::AddDataChannelFromOpenMessage(
<< "are not supported.";
return false;
}
if (data_channels_.find(label) != data_channels_.end()) {
LOG(LS_ERROR) << "DataChannel with label " << label
<< " already exists.";
return false;
}
scoped_refptr<DataChannel> channel(
data_channel_factory_->CreateDataChannel(label, &config));
if (!channel.get()) {
LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
return false;
}
data_channels_[label] = channel;
sctp_data_channels_.push_back(channel);
stream_observer_->OnAddDataChannel(channel);
return true;
}
@ -464,10 +464,13 @@ void MediaStreamSignaling::OnVideoChannelClose() {
}
void MediaStreamSignaling::OnDataChannelClose() {
DataChannels::iterator it = data_channels_.begin();
for (; it != data_channels_.end(); ++it) {
DataChannel* data_channel = it->second;
data_channel->OnDataEngineClose();
RtpDataChannels::iterator it1 = rtp_data_channels_.begin();
for (; it1 != rtp_data_channels_.end(); ++it1) {
it1->second->OnDataEngineClose();
}
SctpDataChannels::iterator it2 = sctp_data_channels_.begin();
for (; it2 != sctp_data_channels_.end(); ++it2) {
(*it2)->OnDataEngineClose();
}
}
@ -525,8 +528,8 @@ void MediaStreamSignaling::UpdateSessionOptions() {
}
// Check for data channels.
DataChannels::const_iterator data_channel_it = data_channels_.begin();
for (; data_channel_it != data_channels_.end(); ++data_channel_it) {
RtpDataChannels::const_iterator data_channel_it = rtp_data_channels_.begin();
for (; data_channel_it != rtp_data_channels_.end(); ++data_channel_it) {
const DataChannel* channel = data_channel_it->second;
if (channel->state() == DataChannel::kConnecting ||
channel->state() == DataChannel::kOpen) {
@ -843,8 +846,9 @@ void MediaStreamSignaling::UpdateLocalRtpDataChannels(
// For MediaStreams, the sync_label is the MediaStream label and the
// track label is the same as |streamid|.
const std::string& channel_label = it->sync_label;
DataChannels::iterator data_channel_it = data_channels_.find(channel_label);
if (!VERIFY(data_channel_it != data_channels_.end())) {
RtpDataChannels::iterator data_channel_it =
rtp_data_channels_.find(channel_label);
if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
continue;
}
// Set the SSRC the data channel should use for sending.
@ -866,9 +870,9 @@ void MediaStreamSignaling::UpdateRemoteRtpDataChannels(
// does not exist. Ex a=ssrc:444330170 mslabel:test1.
std::string label = it->sync_label.empty() ?
talk_base::ToString(it->first_ssrc()) : it->sync_label;
DataChannels::iterator data_channel_it =
data_channels_.find(label);
if (data_channel_it == data_channels_.end()) {
RtpDataChannels::iterator data_channel_it =
rtp_data_channels_.find(label);
if (data_channel_it == rtp_data_channels_.end()) {
// This is a new data channel.
CreateRemoteDataChannel(label, it->first_ssrc());
} else {
@ -882,8 +886,8 @@ void MediaStreamSignaling::UpdateRemoteRtpDataChannels(
void MediaStreamSignaling::UpdateClosingDataChannels(
const std::vector<std::string>& active_channels, bool is_local_update) {
DataChannels::iterator it = data_channels_.begin();
while (it != data_channels_.end()) {
RtpDataChannels::iterator it = rtp_data_channels_.begin();
while (it != rtp_data_channels_.end()) {
DataChannel* data_channel = it->second;
if (std::find(active_channels.begin(), active_channels.end(),
data_channel->label()) != active_channels.end()) {
@ -897,8 +901,8 @@ void MediaStreamSignaling::UpdateClosingDataChannels(
data_channel->RemotePeerRequestClose();
if (data_channel->state() == DataChannel::kClosed) {
data_channels_.erase(it);
it = data_channels_.begin();
rtp_data_channels_.erase(it);
it = rtp_data_channels_.begin();
} else {
++it;
}
@ -914,29 +918,32 @@ void MediaStreamSignaling::CreateRemoteDataChannel(const std::string& label,
}
scoped_refptr<DataChannel> channel(
data_channel_factory_->CreateDataChannel(label, NULL));
if (!channel.get()) {
LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
<< "CreateDataChannel failed.";
return;
}
channel->SetReceiveSsrc(remote_ssrc);
stream_observer_->OnAddDataChannel(channel);
}
void MediaStreamSignaling::OnDataTransportCreatedForSctp() {
DataChannels::iterator it = data_channels_.begin();
for (; it != data_channels_.end(); ++it) {
DataChannel* data_channel = it->second;
data_channel->OnTransportChannelCreated();
SctpDataChannels::iterator it = sctp_data_channels_.begin();
for (; it != sctp_data_channels_.end(); ++it) {
(*it)->OnTransportChannelCreated();
}
}
void MediaStreamSignaling::OnDtlsRoleReadyForSctp(talk_base::SSLRole role) {
DataChannels::iterator it = data_channels_.begin();
for (; it != data_channels_.end(); ++it) {
DataChannel* data_channel = it->second;
if (data_channel->id() < 0) {
SctpDataChannels::iterator it = sctp_data_channels_.begin();
for (; it != sctp_data_channels_.end(); ++it) {
if ((*it)->id() < 0) {
int sid;
if (!AllocateSctpSid(role, &sid)) {
LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
continue;
}
data_channel->SetSctpSid(sid);
(*it)->SetSctpSid(sid);
}
}
}

View File

@ -384,8 +384,10 @@ class MediaStreamSignaling {
int last_allocated_sctp_odd_sid_;
typedef std::map<std::string, talk_base::scoped_refptr<DataChannel> >
DataChannels;
DataChannels data_channels_;
RtpDataChannels;
typedef std::vector<talk_base::scoped_refptr<DataChannel> > SctpDataChannels;
RtpDataChannels rtp_data_channels_;
SctpDataChannels sctp_data_channels_;
};
} // namespace webrtc

View File

@ -238,6 +238,23 @@ static bool CompareStreamCollections(StreamCollectionInterface* s1,
return true;
}
class FakeDataChannelFactory : public webrtc::DataChannelFactory {
public:
FakeDataChannelFactory(FakeDataChannelProvider* provider,
cricket::DataChannelType dct)
: provider_(provider), type_(dct) {}
virtual talk_base::scoped_refptr<webrtc::DataChannel> CreateDataChannel(
const std::string& label,
const webrtc::DataChannelInit* config) {
return webrtc::DataChannel::Create(provider_, type_, label, config);
}
private:
FakeDataChannelProvider* provider_;
cricket::DataChannelType type_;
};
class MockSignalingObserver : public webrtc::MediaStreamSignalingObserver {
public:
MockSignalingObserver()
@ -418,6 +435,7 @@ class MediaStreamSignalingTest: public testing::Test {
talk_base::Thread::Current()));
signaling_.reset(new MediaStreamSignalingForTest(observer_.get(),
channel_manager_.get()));
data_channel_provider_.reset(new FakeDataChannelProvider());
}
// Create a collection of streams.
@ -508,12 +526,25 @@ class MediaStreamSignalingTest: public testing::Test {
ASSERT_TRUE(stream->AddTrack(video_track));
}
talk_base::scoped_refptr<webrtc::DataChannel> AddDataChannel(
cricket::DataChannelType type, const std::string& label, int id) {
webrtc::DataChannelInit config;
config.id = id;
talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
webrtc::DataChannel::Create(
data_channel_provider_.get(), type, label, &config));
EXPECT_TRUE(data_channel.get() != NULL);
EXPECT_TRUE(signaling_->AddDataChannel(data_channel.get()));
return data_channel;
}
// ChannelManager is used by VideoSource, so it should be released after all
// the video tracks. Put it as the first private variable should ensure that.
talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
talk_base::scoped_refptr<StreamCollection> reference_collection_;
talk_base::scoped_ptr<MockSignalingObserver> observer_;
talk_base::scoped_ptr<MediaStreamSignalingForTest> signaling_;
talk_base::scoped_ptr<FakeDataChannelProvider> data_channel_provider_;
};
// Test that a MediaSessionOptions is created for an offer if
@ -1029,27 +1060,46 @@ TEST_F(MediaStreamSignalingTest, SctpIdAllocationBasedOnRole) {
// Verifies that SCTP ids of existing DataChannels are not reused.
TEST_F(MediaStreamSignalingTest, SctpIdAllocationNoReuse) {
talk_base::scoped_ptr<FakeDataChannelProvider> provider(
new FakeDataChannelProvider());
// Creates a DataChannel with id 1.
webrtc::DataChannelInit config;
config.id = 1;
talk_base::scoped_refptr<webrtc::DataChannel> data_channel(
webrtc::DataChannel::Create(
provider.get(), cricket::DCT_SCTP, "a", &config));
ASSERT_TRUE(data_channel.get() != NULL);
ASSERT_TRUE(signaling_->AddDataChannel(data_channel.get()));
int old_id = 1;
AddDataChannel(cricket::DCT_SCTP, "a", old_id);
int new_id;
ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_SERVER, &new_id));
EXPECT_NE(config.id, new_id);
EXPECT_NE(old_id, new_id);
// Creates a DataChannel with id 0.
config.id = 0;
data_channel = webrtc::DataChannel::Create(
provider.get(), cricket::DCT_SCTP, "b", &config);
ASSERT_TRUE(data_channel.get() != NULL);
ASSERT_TRUE(signaling_->AddDataChannel(data_channel.get()));
old_id = 0;
AddDataChannel(cricket::DCT_SCTP, "a", old_id);
ASSERT_TRUE(signaling_->AllocateSctpSid(talk_base::SSL_CLIENT, &new_id));
EXPECT_NE(config.id, new_id);
EXPECT_NE(old_id, new_id);
}
// Verifies that duplicated label is not allowed for RTP data channel.
TEST_F(MediaStreamSignalingTest, RtpDuplicatedLabelNotAllowed) {
AddDataChannel(cricket::DCT_RTP, "a", -1);
webrtc::DataChannelInit config;
talk_base::scoped_refptr<webrtc::DataChannel> data_channel =
webrtc::DataChannel::Create(
data_channel_provider_.get(), cricket::DCT_RTP, "a", &config);
ASSERT_TRUE(data_channel.get() != NULL);
EXPECT_FALSE(signaling_->AddDataChannel(data_channel.get()));
}
// Verifies that duplicated label is allowed for SCTP data channel.
TEST_F(MediaStreamSignalingTest, SctpDuplicatedLabelAllowed) {
AddDataChannel(cricket::DCT_SCTP, "a", -1);
AddDataChannel(cricket::DCT_SCTP, "a", -1);
}
// Verifies that duplicated label from OPEN message is allowed.
TEST_F(MediaStreamSignalingTest, DuplicatedLabelFromOpenMessageAllowed) {
AddDataChannel(cricket::DCT_SCTP, "a", -1);
FakeDataChannelFactory fake_factory(data_channel_provider_.get(),
cricket::DCT_SCTP);
signaling_->SetDataChannelFactory(&fake_factory);
webrtc::DataChannelInit config;
config.id = 0;
EXPECT_TRUE(signaling_->AddDataChannelFromOpenMessage("a", config));
}

View File

@ -42,8 +42,6 @@ namespace {
using webrtc::PeerConnectionInterface;
// The min number of tokens in the ice uri.
static const size_t kMinIceUriTokens = 2;
// The min number of tokens must present in Turn host uri.
// e.g. user@turn.example.org
static const size_t kTurnHostTokensNum = 2;
@ -103,6 +101,73 @@ struct GetStatsMsg : public talk_base::MessageData {
talk_base::scoped_refptr<webrtc::StatsObserver> observer;
};
// |in_str| should be of format
// stunURI = scheme ":" stun-host [ ":" stun-port ]
// scheme = "stun" / "stuns"
// stun-host = IP-literal / IPv4address / reg-name
// stun-port = *DIGIT
// draft-petithuguenin-behave-turn-uris-01
// turnURI = scheme ":" turn-host [ ":" turn-port ]
// turn-host = username@IP-literal / IPv4address / reg-name
bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
ServiceType* service_type,
std::string* hostname) {
std::string::size_type colonpos = in_str.find(':');
if (colonpos == std::string::npos) {
return false;
}
std::string type = in_str.substr(0, colonpos);
for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
if (type.compare(kValidIceServiceTypes[i]) == 0) {
*service_type = static_cast<ServiceType>(i);
break;
}
}
if (*service_type == INVALID) {
return false;
}
*hostname = in_str.substr(colonpos + 1, std::string::npos);
return true;
}
// This method parses IPv6 and IPv4 literal strings, along with hostnames in
// standard hostname:port format.
// Consider following formats as correct.
// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
// |hostname|, |[IPv6 address]|, |IPv4 address|
bool ParseHostnameAndPortFromString(const std::string& in_str,
std::string* host,
int* port) {
if (in_str.at(0) == '[') {
std::string::size_type closebracket = in_str.rfind(']');
if (closebracket != std::string::npos) {
*host = in_str.substr(1, closebracket - 1);
std::string::size_type colonpos = in_str.find(':', closebracket);
if (std::string::npos != colonpos) {
if (!talk_base::FromString(
in_str.substr(closebracket + 2, std::string::npos), port)) {
return false;
}
}
} else {
return false;
}
} else {
std::string::size_type colonpos = in_str.find(':');
if (std::string::npos != colonpos) {
*host = in_str.substr(0, colonpos);
if (!talk_base::FromString(
in_str.substr(colonpos + 1, std::string::npos), port)) {
return false;
}
} else {
*host = in_str;
}
}
return true;
}
typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
StunConfiguration;
typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
@ -125,8 +190,6 @@ bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
// transport-ext = 1*unreserved
// turn-host = IP-literal / IPv4address / reg-name
// turn-port = *DIGIT
// TODO(ronghuawu): Handle IPV6 address
for (size_t i = 0; i < configuration.size(); ++i) {
webrtc::PeerConnectionInterface::IceServer server = configuration[i];
if (server.uri.empty()) {
@ -152,41 +215,40 @@ bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
}
}
tokens.clear();
talk_base::tokenize(uri_without_transport, ':', &tokens);
if (tokens.size() < kMinIceUriTokens) {
LOG(WARNING) << "Invalid uri: " << server.uri;
continue;
}
std::string hoststring;
ServiceType service_type = INVALID;
const std::string& type = tokens[0];
for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
if (type.compare(kValidIceServiceTypes[i]) == 0) {
service_type = static_cast<ServiceType>(i);
break;
}
}
if (service_type == INVALID) {
LOG(WARNING) << "Invalid service type: " << type;
if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
&service_type,
&hoststring)) {
LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
<< uri_without_transport;
continue;
}
std::string address = tokens[1];
// Let's break hostname.
tokens.clear();
talk_base::tokenize(hoststring, '@', &tokens);
hoststring = tokens[0];
if (tokens.size() == kTurnHostTokensNum) {
server.username = talk_base::s_url_decode(tokens[0]);
hoststring = tokens[1];
}
int port = kDefaultStunPort;
std::string address;
if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
continue;
}
if (service_type == TURNS) {
port = kDefaultStunTlsPort;
turn_transport_type = kTcpTransportType;
}
if (tokens.size() > kMinIceUriTokens) {
if (!talk_base::FromString(tokens[2], &port)) {
LOG(LS_WARNING) << "Failed to parse port string: " << tokens[2];
continue;
}
if (port <= 0 || port > 0xffff) {
LOG(WARNING) << "Invalid port: " << port;
continue;
}
if (port <= 0 || port > 0xffff) {
LOG(WARNING) << "Invalid port: " << port;
continue;
}
switch (service_type) {

View File

@ -69,6 +69,15 @@ static const char kTurnPassword[] = "turnpassword";
static const int kDefaultStunPort = 3478;
static const int kDefaultStunTlsPort = 5349;
static const char kTurnUsername[] = "test";
static const char kStunIceServerWithIPv4Address[] = "stun:1.2.3.4:1234";
static const char kStunIceServerWithIPv4AddressWithoutPort[] = "stun:1.2.3.4";
static const char kStunIceServerWithIPv6Address[] = "stun:[2401:fa00:4::]:1234";
static const char kStunIceServerWithIPv6AddressWithoutPort[] =
"stun:[2401:fa00:4::]";
static const char kStunIceServerWithInvalidIPv6Address[] =
"stun:[2401:fa00:4:::3478";
static const char kTurnIceServerWithIPv6Address[] =
"turn:test@[2401:fa00:4::]:1234";
class NullPeerConnectionObserver : public PeerConnectionObserver {
public:
@ -265,6 +274,51 @@ TEST_F(PeerConnectionFactoryTest, CreatePCUsingSecureTurnUrl) {
VerifyTurnConfigurations(turn_configs);
}
TEST_F(PeerConnectionFactoryTest, CreatePCUsingIPLiteralAddress) {
webrtc::PeerConnectionInterface::IceServers ice_servers;
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = kStunIceServerWithIPv4Address;
ice_servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv4AddressWithoutPort;
ice_servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv6Address;
ice_servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithIPv6AddressWithoutPort;
ice_servers.push_back(ice_server);
ice_server.uri = kStunIceServerWithInvalidIPv6Address;
ice_servers.push_back(ice_server);
ice_server.uri = kTurnIceServerWithIPv6Address;
ice_server.password = kTurnPassword;
ice_servers.push_back(ice_server);
talk_base::scoped_refptr<PeerConnectionInterface> pc(
factory_->CreatePeerConnection(ice_servers, NULL,
allocator_factory_.get(),
NULL,
&observer_));
EXPECT_TRUE(pc.get() != NULL);
StunConfigurations stun_configs;
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun1(
"1.2.3.4", 1234);
stun_configs.push_back(stun1);
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun2(
"1.2.3.4", 3478);
stun_configs.push_back(stun2); // Default port
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun3(
"2401:fa00:4::", 1234);
stun_configs.push_back(stun3);
webrtc::PortAllocatorFactoryInterface::StunConfiguration stun4(
"2401:fa00:4::", 3478);
stun_configs.push_back(stun4); // Default port
// Turn Address has the same host information as |stun3|.
stun_configs.push_back(stun3);
VerifyStunConfigurations(stun_configs);
TurnConfigurations turn_configs;
webrtc::PortAllocatorFactoryInterface::TurnConfiguration turn1(
"2401:fa00:4::", 1234, "test", kTurnPassword, "udp", false);
turn_configs.push_back(turn1);
VerifyTurnConfigurations(turn_configs);
}
// This test verifies the captured stream is rendered locally using a
// local video track.
TEST_F(PeerConnectionFactoryTest, LocalRendering) {

View File

@ -37,6 +37,7 @@
#include "talk/app/webrtc/videosource.h"
#include "talk/base/gunit.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/ssladapter.h"
#include "talk/base/sslstreamadapter.h"
#include "talk/base/stringutils.h"
#include "talk/base/thread.h"
@ -227,12 +228,17 @@ class MockPeerConnectionObserver : public PeerConnectionObserver {
class PeerConnectionInterfaceTest : public testing::Test {
protected:
virtual void SetUp() {
talk_base::InitializeSSL(NULL);
pc_factory_ = webrtc::CreatePeerConnectionFactory(
talk_base::Thread::Current(), talk_base::Thread::Current(), NULL, NULL,
NULL);
ASSERT_TRUE(pc_factory_.get() != NULL);
}
virtual void TearDown() {
talk_base::CleanupSSL();
}
void CreatePeerConnection() {
CreatePeerConnection("", "", NULL);
}
@ -1070,9 +1076,7 @@ TEST_F(PeerConnectionInterfaceTest, TestRejectDataChannelInAnswer) {
// Test that we can create a session description from an SDP string from
// FireFox, use it as a remote session description, generate an answer and use
// the answer as a local description.
// TODO(mallinath): re-enable per
// https://code.google.com/p/webrtc/issues/detail?id=2574
TEST_F(PeerConnectionInterfaceTest, DISABLED_ReceiveFireFoxOffer) {
TEST_F(PeerConnectionInterfaceTest, ReceiveFireFoxOffer) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
FakeConstraints constraints;
constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
@ -1096,11 +1100,12 @@ TEST_F(PeerConnectionInterfaceTest, DISABLED_ReceiveFireFoxOffer) {
cricket::GetFirstVideoContent(pc_->local_description()->description());
ASSERT_TRUE(content != NULL);
EXPECT_FALSE(content->rejected);
#ifdef HAVE_SCTP
content =
cricket::GetFirstDataContent(pc_->local_description()->description());
ASSERT_TRUE(content != NULL);
EXPECT_TRUE(content->rejected);
#endif
}
// Test that we can create an audio only offer and receive an answer with a

View File

@ -64,29 +64,17 @@ class FakeDataChannelProvider : public webrtc::DataChannelProviderInterface {
connected_channels_.erase(data_channel);
}
virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE {
if (!transport_available_) {
return;
}
send_ssrcs_.insert(send_ssrc);
recv_ssrcs_.insert(recv_ssrc);
}
virtual void AddSctpDataStream(uint32 sid) OVERRIDE {
if (!transport_available_) {
return;
}
AddRtpDataStream(sid, sid);
}
virtual void RemoveRtpDataStream(
uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE {
send_ssrcs_.erase(send_ssrc);
recv_ssrcs_.erase(recv_ssrc);
send_ssrcs_.insert(sid);
recv_ssrcs_.insert(sid);
}
virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE {
RemoveRtpDataStream(sid, sid);
send_ssrcs_.erase(sid);
recv_ssrcs_.erase(sid);
}
virtual bool ReadyToSendData() const OVERRIDE {

View File

@ -75,6 +75,7 @@ static const char kFireFoxSdpOffer[] =
"a=candidate:4 2 UDP 2113667326 10.0.254.2 58890 typ host\r\n"
"a=candidate:5 2 UDP 1694302206 74.95.2.170 33611 typ srflx raddr"
" 10.0.254.2 rport 58890\r\n"
#ifdef HAVE_SCTP
"m=application 45536 SCTP/DTLS 5000\r\n"
"c=IN IP4 74.95.2.170\r\n"
"a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n"
@ -88,7 +89,9 @@ static const char kFireFoxSdpOffer[] =
"a=candidate:2 2 UDP 2112487678 172.16.131.1 59635 typ host\r\n"
"a=candidate:4 2 UDP 2113667326 10.0.254.2 61232 typ host\r\n"
"a=candidate:5 2 UDP 1694302206 74.95.2.170 45468 typ srflx raddr"
" 10.0.254.2 rport 61232\r\n";
" 10.0.254.2 rport 61232\r\n"
#endif
;
// Audio SDP with a limited set of audio codecs.
static const char kAudioSdp[] =

View File

@ -997,31 +997,23 @@ void WebRtcSession::DisconnectDataChannel(DataChannel* webrtc_data_channel) {
data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
}
void WebRtcSession::AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) {
void WebRtcSession::AddSctpDataStream(uint32 sid) {
if (!data_channel_.get()) {
LOG(LS_ERROR) << "AddDataChannelStreams called when data_channel_ is NULL.";
return;
}
data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(recv_ssrc));
data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(send_ssrc));
data_channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(sid));
data_channel_->AddSendStream(cricket::StreamParams::CreateLegacy(sid));
}
void WebRtcSession::AddSctpDataStream(uint32 sid) {
AddRtpDataStream(sid, sid);
}
void WebRtcSession::RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) {
void WebRtcSession::RemoveSctpDataStream(uint32 sid) {
if (!data_channel_.get()) {
LOG(LS_ERROR) << "RemoveDataChannelStreams called when data_channel_ is "
<< "NULL.";
return;
}
data_channel_->RemoveRecvStream(recv_ssrc);
data_channel_->RemoveSendStream(send_ssrc);
}
void WebRtcSession::RemoveSctpDataStream(uint32 sid) {
RemoveRtpDataStream(sid, sid);
data_channel_->RemoveRecvStream(sid);
data_channel_->RemoveSendStream(sid);
}
bool WebRtcSession::ReadyToSendData() const {

View File

@ -190,9 +190,7 @@ class WebRtcSession : public cricket::BaseSession,
cricket::SendDataResult* result) OVERRIDE;
virtual bool ConnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE;
virtual void DisconnectDataChannel(DataChannel* webrtc_data_channel) OVERRIDE;
virtual void AddRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE;
virtual void AddSctpDataStream(uint32 sid) OVERRIDE;
virtual void RemoveRtpDataStream(uint32 send_ssrc, uint32 recv_ssrc) OVERRIDE;
virtual void RemoveSctpDataStream(uint32 sid) OVERRIDE;
virtual bool ReadyToSendData() const OVERRIDE;

View File

@ -0,0 +1,64 @@
/*
* libjingle
* Copyright 2013, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TALK_BASE_ASYNCRESOLVERINTERFACE_H_
#define TALK_BASE_ASYNCRESOLVERINTERFACE_H_
#include "talk/base/sigslot.h"
#include "talk/base/socketaddress.h"
namespace talk_base {
// This interface defines the methods to resolve the address asynchronously.
class AsyncResolverInterface {
public:
AsyncResolverInterface() {}
virtual ~AsyncResolverInterface() {}
// Start address resolve process.
virtual void Start(const SocketAddress& addr) = 0;
// Returns top most resolved address of |family|
virtual bool GetResolvedAddress(int family, SocketAddress* addr) const = 0;
// Returns error from resolver.
virtual int GetError() const = 0;
// Delete the resolver.
virtual void Destroy(bool wait) = 0;
// Returns top most resolved IPv4 address if address is resolved successfully.
// Otherwise returns address set in SetAddress.
SocketAddress address() const {
SocketAddress addr;
GetResolvedAddress(AF_INET, &addr);
return addr;
}
// This signal is fired when address resolve process is completed.
sigslot::signal1<AsyncResolverInterface*> SignalDone;
};
} // namespace talk_base
#endif

View File

@ -82,7 +82,10 @@ void AutoDetectProxy::DoWork() {
}
void AutoDetectProxy::OnMessage(Message *msg) {
if (MSG_TIMEOUT == msg->message_id) {
if (MSG_UNRESOLVABLE == msg->message_id) {
// If we can't resolve the proxy, skip straight to failure.
Complete(PROXY_UNKNOWN);
} else if (MSG_TIMEOUT == msg->message_id) {
OnCloseEvent(socket_, ETIMEDOUT);
} else {
// This must be the ST_MSG_WORKER_DONE message that deletes the
@ -136,22 +139,24 @@ void AutoDetectProxy::OnMessage(Message *msg) {
}
}
void AutoDetectProxy::OnResolveResult(SignalThread* thread) {
if (thread != resolver_) {
void AutoDetectProxy::OnResolveResult(AsyncResolverInterface* resolver) {
if (resolver != resolver_) {
return;
}
int error = resolver_->error();
int error = resolver_->GetError();
if (error == 0) {
LOG(LS_VERBOSE) << "Resolved " << proxy_.address << " to "
<< resolver_->address();
proxy_.address = resolver_->address();
DoConnect();
if (!DoConnect()) {
Thread::Current()->Post(this, MSG_TIMEOUT);
}
} else {
LOG(LS_INFO) << "Failed to resolve " << resolver_->address();
resolver_->Destroy(false);
resolver_ = NULL;
proxy_.address = SocketAddress();
Thread::Current()->Post(this, MSG_TIMEOUT);
Thread::Current()->Post(this, MSG_UNRESOLVABLE);
}
}
@ -166,6 +171,7 @@ void AutoDetectProxy::Next() {
if (socket_) {
Thread::Current()->Clear(this, MSG_TIMEOUT);
Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
socket_->Close();
Thread::Current()->Dispose(socket_);
socket_ = NULL;
@ -177,17 +183,18 @@ void AutoDetectProxy::Next() {
if (!resolver_) {
resolver_ = new AsyncResolver();
}
resolver_->set_address(proxy_.address);
resolver_->SignalWorkDone.connect(this,
&AutoDetectProxy::OnResolveResult);
resolver_->Start();
resolver_->SignalDone.connect(this, &AutoDetectProxy::OnResolveResult);
resolver_->Start(proxy_.address);
} else {
DoConnect();
if (!DoConnect()) {
Thread::Current()->Post(this, MSG_TIMEOUT);
return;
}
}
Thread::Current()->PostDelayed(timeout, this, MSG_TIMEOUT);
}
void AutoDetectProxy::DoConnect() {
bool AutoDetectProxy::DoConnect() {
if (resolver_) {
resolver_->Destroy(false);
resolver_ = NULL;
@ -197,16 +204,18 @@ void AutoDetectProxy::DoConnect() {
proxy_.address.family(), SOCK_STREAM);
if (!socket_) {
LOG(LS_VERBOSE) << "Unable to create socket for " << proxy_.address;
return;
return false;
}
socket_->SignalConnectEvent.connect(this, &AutoDetectProxy::OnConnectEvent);
socket_->SignalReadEvent.connect(this, &AutoDetectProxy::OnReadEvent);
socket_->SignalCloseEvent.connect(this, &AutoDetectProxy::OnCloseEvent);
socket_->Connect(proxy_.address);
return true;
}
void AutoDetectProxy::Complete(ProxyType type) {
Thread::Current()->Clear(this, MSG_TIMEOUT);
Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
if (socket_) {
socket_->Close();
}

View File

@ -42,7 +42,7 @@ namespace talk_base {
// AutoDetectProxy
///////////////////////////////////////////////////////////////////////////////
class AsyncResolver;
class AsyncResolverInterface;
class AsyncSocket;
class AutoDetectProxy : public SignalThread {
@ -72,6 +72,7 @@ class AutoDetectProxy : public SignalThread {
return GetProxySettingsForUrl(agent, url, proxy, true);
}
enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
MSG_UNRESOLVABLE,
ADP_MSG_FIRST_AVAILABLE};
protected:
@ -87,14 +88,14 @@ class AutoDetectProxy : public SignalThread {
void OnConnectEvent(AsyncSocket * socket);
void OnReadEvent(AsyncSocket * socket);
void OnCloseEvent(AsyncSocket * socket, int error);
void OnResolveResult(SignalThread* thread);
void DoConnect();
void OnResolveResult(AsyncResolverInterface* resolver);
bool DoConnect();
private:
std::string agent_;
std::string server_url_;
ProxyInfo proxy_;
AsyncResolver* resolver_;
AsyncResolverInterface* resolver_;
AsyncSocket* socket_;
int next_;

View File

@ -37,9 +37,16 @@ static const char kPath[] = "/";
static const char kHost[] = "relay.google.com";
static const uint16 kPort = 443;
static const bool kSecure = true;
// Each of the two stages in AutoDetectProxy has a 2-second time-out, so 5
// seconds total should be enough.
static const int kTimeoutMs = 5000;
// At most, AutoDetectProxy should take ~6 seconds. Each connect step is
// allotted 2 seconds, with the initial resolution + connect given an
// extra 2 seconds. The slowest case is:
// 1) Resolution + HTTPS takes full 4 seconds and fails (but resolution
// succeeds).
// 2) SOCKS5 takes the full 2 seconds.
// Socket creation time seems unbounded, and has been observed to take >1 second
// on a linux machine under load. As such, we allow for 10 seconds for timeout,
// though could still end up with some flakiness.
static const int kTimeoutMs = 10000;
class AutoDetectProxyTest : public testing::Test, public sigslot::has_slots<> {
public:

View File

@ -316,11 +316,11 @@ void HttpClient::reset() {
base_.abort(HE_OPERATION_CANCELLED);
}
void HttpClient::OnResolveResult(SignalThread* thread) {
if (thread != resolver_) {
void HttpClient::OnResolveResult(AsyncResolverInterface* resolver) {
if (resolver != resolver_) {
return;
}
int error = resolver_->error();
int error = resolver_->GetError();
server_ = resolver_->address();
resolver_->Destroy(false);
resolver_ = NULL;
@ -335,9 +335,8 @@ void HttpClient::OnResolveResult(SignalThread* thread) {
void HttpClient::StartDNSLookup() {
resolver_ = new AsyncResolver();
resolver_->set_address(server_);
resolver_->SignalWorkDone.connect(this, &HttpClient::OnResolveResult);
resolver_->Start();
resolver_->SignalDone.connect(this, &HttpClient::OnResolveResult);
resolver_->Start(server_);
}
void HttpClient::set_server(const SocketAddress& address) {

View File

@ -175,7 +175,7 @@ protected:
HttpError OnHeaderAvailable(bool ignore_data, bool chunked, size_t data_size);
void StartDNSLookup();
void OnResolveResult(SignalThread* thread);
void OnResolveResult(AsyncResolverInterface* resolver);
// IHttpNotify Interface
virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size);
@ -199,7 +199,7 @@ private:
scoped_ptr<HttpAuthContext> context_;
DiskCache* cache_;
CacheState cache_state_;
AsyncResolver* resolver_;
AsyncResolverInterface* resolver_;
};
//////////////////////////////////////////////////////////////////////

View File

@ -109,7 +109,23 @@ bool LateBindingSymbolTable::LoadFromPath(const char *dll_path) {
}
#ifdef POSIX
handle_ = dlopen(dll_path, RTLD_NOW);
handle_ = dlopen(dll_path,
// RTLD_NOW front-loads symbol resolution so that errors are
// caught early instead of causing a process abort later.
// RTLD_LOCAL prevents other modules from automatically
// seeing symbol definitions in the newly-loaded tree. This
// is necessary for same-named symbols in different ABI
// versions of the same library to not explode.
RTLD_NOW|RTLD_LOCAL
#ifdef LINUX
// RTLD_DEEPBIND makes symbol dependencies in the
// newly-loaded tree prefer to resolve to definitions within
// that tree (the default on OS X). This is necessary for
// same-named symbols in different ABI versions of the same
// library to not explode.
|RTLD_DEEPBIND
#endif
); // NOLINT
#else
#error Not implemented
#endif

View File

@ -33,7 +33,7 @@ namespace talk_base {
#define LATE_BINDING_SYMBOL_TABLE_CLASS_NAME LIBDBUS_GLIB_CLASS_NAME
#define LATE_BINDING_SYMBOL_TABLE_SYMBOLS_LIST LIBDBUS_GLIB_SYMBOLS_LIST
#define LATE_BINDING_SYMBOL_TABLE_DLL_NAME "libdbus-glib-1.so"
#define LATE_BINDING_SYMBOL_TABLE_DLL_NAME "libdbus-glib-1.so.2"
#include "talk/base/latebindingsymboltable.cc.def"
} // namespace talk_base

View File

@ -87,7 +87,7 @@ void MacAsyncSocket::OnResolveResult(SignalThread* thread) {
if (thread != resolver_) {
return;
}
int error = resolver_->error();
int error = resolver_->GetError();
if (error == 0) {
error = DoConnect(resolver_->address());
} else {
@ -109,10 +109,9 @@ int MacAsyncSocket::Connect(const SocketAddress& addr) {
if (addr.IsUnresolved()) {
LOG(LS_VERBOSE) << "Resolving addr in MacAsyncSocket::Connect";
resolver_ = new AsyncResolver();
resolver_->set_address(addr);
resolver_->SignalWorkDone.connect(this,
&MacAsyncSocket::OnResolveResult);
resolver_->Start();
resolver_->Start(addr);
state_ = CS_CONNECTING;
return 0;
}

View File

@ -67,7 +67,27 @@ int ResolveHostname(const std::string& hostname, int family,
}
// AsyncResolver
AsyncResolver::AsyncResolver() : error_(0) {
AsyncResolver::AsyncResolver() : error_(-1) {
}
void AsyncResolver::Start(const SocketAddress& addr) {
addr_ = addr;
// SignalThred Start will kickoff the resolve process.
SignalThread::Start();
}
bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
if (error_ != 0 || addresses_.empty())
return false;
*addr = addr_;
for (size_t i = 0; i < addresses_.size(); ++i) {
if (family == addresses_[i].family()) {
addr->SetIP(addresses_[i]);
return true;
}
}
return false;
}
void AsyncResolver::DoWork() {
@ -76,9 +96,7 @@ void AsyncResolver::DoWork() {
}
void AsyncResolver::OnWorkDone() {
if (addresses_.size() > 0) {
addr_.SetIP(addresses_[0]);
}
SignalDone(this);
}
const char* inet_ntop(int af, const void *src, char* dst, socklen_t size) {

View File

@ -37,25 +37,30 @@
#include <list>
#include "talk/base/asyncresolverinterface.h"
#include "talk/base/signalthread.h"
#include "talk/base/sigslot.h"
#include "talk/base/socketaddress.h"
namespace talk_base {
class AsyncResolverTest;
// AsyncResolver will perform async DNS resolution, signaling the result on
// the inherited SignalWorkDone when the operation completes.
class AsyncResolver : public SignalThread {
// the SignalDone from AsyncResolverInterface when the operation completes.
class AsyncResolver : public SignalThread, public AsyncResolverInterface {
public:
AsyncResolver();
virtual ~AsyncResolver() {}
virtual void Start(const SocketAddress& addr);
virtual bool GetResolvedAddress(int family, SocketAddress* addr) const;
virtual int GetError() const { return error_; }
virtual void Destroy(bool wait) { SignalThread::Destroy(wait); }
const SocketAddress& address() const { return addr_; }
const std::vector<IPAddress>& addresses() const { return addresses_; }
void set_address(const SocketAddress& addr) { addr_ = addr; }
int error() const { return error_; }
void set_error(int error) { error_ = error; }
protected:
virtual void DoWork();
virtual void OnWorkDone();

View File

@ -200,9 +200,8 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
if (addr.IsUnresolved()) {
LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect";
resolver_ = new AsyncResolver();
resolver_->set_address(addr);
resolver_->SignalWorkDone.connect(this, &PhysicalSocket::OnResolveResult);
resolver_->Start();
resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult);
resolver_->Start(addr);
state_ = CS_CONNECTING;
return 0;
}
@ -476,12 +475,12 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
SocketServer* socketserver() { return ss_; }
protected:
void OnResolveResult(SignalThread* thread) {
if (thread != resolver_) {
void OnResolveResult(AsyncResolverInterface* resolver) {
if (resolver != resolver_) {
return;
}
int error = resolver_->error();
int error = resolver_->GetError();
if (error == 0) {
error = DoConnect(resolver_->address());
} else {

View File

@ -134,17 +134,16 @@ void PeerConnectionClient::Connect(const std::string& server, int port,
if (server_address_.IsUnresolved()) {
state_ = RESOLVING;
resolver_ = new talk_base::AsyncResolver();
resolver_->SignalWorkDone.connect(this,
&PeerConnectionClient::OnResolveResult);
resolver_->set_address(server_address_);
resolver_->Start();
resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult);
resolver_->Start(server_address_);
} else {
DoConnect();
}
}
void PeerConnectionClient::OnResolveResult(talk_base::SignalThread *t) {
if (resolver_->error() != 0) {
void PeerConnectionClient::OnResolveResult(
talk_base::AsyncResolverInterface* resolver) {
if (resolver_->GetError() != 0) {
callback_->OnServerConnectionFailure();
resolver_->Destroy(false);
resolver_ = NULL;

View File

@ -121,7 +121,7 @@ class PeerConnectionClient : public sigslot::has_slots<>,
void OnClose(talk_base::AsyncSocket* socket, int err);
void OnResolveResult(talk_base::SignalThread *t);
void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
PeerConnectionClientObserver* callback_;
talk_base::SocketAddress server_address_;

View File

@ -257,6 +257,7 @@
'base/asynchttprequest.cc',
'base/asynchttprequest.h',
'base/asyncpacketsocket.h',
'base/asyncresolverinterface.h',
'base/asyncsocket.cc',
'base/asyncsocket.h',
'base/asynctcpsocket.cc',

View File

@ -42,7 +42,8 @@ namespace cricket {
#undef LATE_BINDING_SYMBOL_TABLE_DLL_NAME
bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0) {
talk_base::DllHandle libudev_1 = dlopen("libudev.so.1", RTLD_NOW|RTLD_NOLOAD);
talk_base::DllHandle libudev_1 = dlopen("libudev.so.1",
RTLD_NOW|RTLD_LOCAL|RTLD_NOLOAD);
bool unsafe_symlink = (libudev_0 == libudev_1);
if (unsafe_symlink) {
// .0 and .1 are distinct ABIs, so if they point to the same thing then one
@ -55,7 +56,8 @@ bool IsWrongLibUDevAbiVersion(talk_base::DllHandle libudev_0) {
// system library loaded the new ABI separately. This is not a problem for
// LateBindingSymbolTable because its symbol look-ups are restricted to its
// DllHandle, but having libudev.so.0 resident may cause problems for that
// system library because symbol names are not namespaced by DLL.
// system library because symbol names are not namespaced by DLL. (Although
// our use of RTLD_LOCAL should avoid most problems.)
LOG(LS_WARNING)
<< "libudev.so.1 is resident but distinct from libudev.so.0";
}

View File

@ -3219,7 +3219,8 @@ bool WebRtcVideoMediaChannel::SetNackFec(int channel_id,
LOG_RTCERR1(SetNACKStatus, channel_id);
return false;
}
LOG(LS_INFO) << "NACK enabled for channel " << channel_id;
std::string enabled = nack_enabled ? "enabled" : "disabled";
LOG(LS_INFO) << "NACK " << enabled << " for channel " << channel_id;
}
return true;
}

View File

@ -3065,9 +3065,12 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
static_cast<float>(ns.currentExpandRate) / (1 << 14);
}
if (engine()->voe()->sync()) {
int jitter_buffer_delay_ms = 0;
int playout_buffer_delay_ms = 0;
engine()->voe()->sync()->GetDelayEstimate(
*it, &rinfo.delay_estimate_ms, &playout_buffer_delay_ms);
*it, &jitter_buffer_delay_ms, &playout_buffer_delay_ms);
rinfo.delay_estimate_ms = jitter_buffer_delay_ms +
playout_buffer_delay_ms;
}
// Get speech level.

View File

@ -30,6 +30,9 @@
#include "talk/base/asyncudpsocket.h"
#include "talk/base/asynctcpsocket.h"
#include "talk/base/logging.h"
#include "talk/base/nethelpers.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketadapters.h"
#include "talk/base/thread.h"
#include "talk/p2p/base/asyncstuntcpsocket.h"
@ -174,6 +177,10 @@ AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
return tcp_socket;
}
AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
return new talk_base::AsyncResolver();
}
int BasicPacketSocketFactory::BindSocket(
AsyncSocket* socket, const SocketAddress& local_address,
int min_port, int max_port) {

View File

@ -51,6 +51,8 @@ class BasicPacketSocketFactory : public PacketSocketFactory {
const SocketAddress& local_address, const SocketAddress& remote_address,
const ProxyInfo& proxy_info, const std::string& user_agent, int opts);
virtual AsyncResolverInterface* CreateAsyncResolver();
private:
int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
int min_port, int max_port);

View File

@ -33,6 +33,7 @@
namespace talk_base {
class AsyncPacketSocket;
class AsyncResolverInterface;
class PacketSocketFactory {
public:
@ -57,6 +58,8 @@ class PacketSocketFactory {
const SocketAddress& local_address, const SocketAddress& remote_address,
const ProxyInfo& proxy_info, const std::string& user_agent, int opts) = 0;
virtual AsyncResolverInterface* CreateAsyncResolver() = 0;
private:
DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
};

View File

@ -162,11 +162,11 @@ static std::string ComputeFoundation(
return talk_base::ToString<uint32>(talk_base::ComputeCrc32(ost.str()));
}
Port::Port(talk_base::Thread* thread, talk_base::Network* network,
const talk_base::IPAddress& ip,
Port::Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
talk_base::Network* network, const talk_base::IPAddress& ip,
const std::string& username_fragment, const std::string& password)
: thread_(thread),
factory_(NULL),
factory_(factory),
send_retransmit_count_attribute_(false),
network_(network),
ip_(ip),

View File

@ -118,8 +118,8 @@ struct ProtocolAddress {
class Port : public PortInterface, public talk_base::MessageHandler,
public sigslot::has_slots<> {
public:
Port(talk_base::Thread* thread, talk_base::Network* network,
const talk_base::IPAddress& ip,
Port(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
talk_base::Network* network, const talk_base::IPAddress& ip,
const std::string& username_fragment, const std::string& password);
Port(talk_base::Thread* thread, const std::string& type,
talk_base::PacketSocketFactory* factory,

View File

@ -766,6 +766,9 @@ class FakePacketSocketFactory : public talk_base::PacketSocketFactory {
void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) {
next_client_tcp_socket_ = next_client_tcp_socket;
}
talk_base::AsyncResolverInterface* CreateAsyncResolver() {
return NULL;
}
private:
AsyncPacketSocket* next_udp_socket_;

View File

@ -125,10 +125,11 @@ class StunBindingRequest : public StunRequest {
};
UDPPort::UDPPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
talk_base::AsyncPacketSocket* socket,
const std::string& username, const std::string& password)
: Port(thread, network, socket->GetLocalAddress().ipaddr(),
: Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
username, password),
requests_(thread),
socket_(socket),
@ -139,10 +140,10 @@ UDPPort::UDPPort(talk_base::Thread* thread,
}
UDPPort::UDPPort(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
const talk_base::IPAddress& ip, int min_port, int max_port,
const std::string& username, const std::string& password)
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
const talk_base::IPAddress& ip, int min_port, int max_port,
const std::string& username, const std::string& password)
: Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
username, password),
requests_(thread),
@ -302,21 +303,21 @@ void UDPPort::ResolveStunAddress() {
if (resolver_)
return;
resolver_ = new talk_base::AsyncResolver();
resolver_->SignalWorkDone.connect(this, &UDPPort::OnResolveResult);
resolver_->set_address(server_addr_);
resolver_->Start();
resolver_ = socket_factory()->CreateAsyncResolver();
resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
resolver_->Start(server_addr_);
}
void UDPPort::OnResolveResult(talk_base::SignalThread* t) {
ASSERT(t == resolver_);
if (resolver_->error() != 0) {
void UDPPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
ASSERT(resolver == resolver_);
if (resolver_->GetError() != 0 ||
!resolver_->GetResolvedAddress(ip().family(), &server_addr_)) {
LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
<< resolver_->error();
<< resolver_->GetError();
OnStunBindingOrResolveRequestFailed();
return;
}
server_addr_ = resolver_->address();
SendStunBindingRequest();
}

View File

@ -46,11 +46,13 @@ namespace cricket {
class UDPPort : public Port {
public:
static UDPPort* Create(talk_base::Thread* thread,
talk_base::PacketSocketFactory* factory,
talk_base::Network* network,
talk_base::AsyncPacketSocket* socket,
const std::string& username,
const std::string& password) {
UDPPort* port = new UDPPort(thread, network, socket, username, password);
UDPPort* port = new UDPPort(thread, factory, network, socket,
username, password);
if (!port->Init()) {
delete port;
port = NULL;
@ -66,8 +68,8 @@ class UDPPort : public Port {
const std::string& username,
const std::string& password) {
UDPPort* port = new UDPPort(thread, factory, network,
ip, min_port, max_port,
username, password);
ip, min_port, max_port,
username, password);
if (!port->Init()) {
delete port;
port = NULL;
@ -114,8 +116,8 @@ class UDPPort : public Port {
int min_port, int max_port,
const std::string& username, const std::string& password);
UDPPort(talk_base::Thread* thread, talk_base::Network* network,
talk_base::AsyncPacketSocket* socket,
UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
talk_base::Network* network, talk_base::AsyncPacketSocket* socket,
const std::string& username, const std::string& password);
bool Init();
@ -141,7 +143,7 @@ class UDPPort : public Port {
private:
// DNS resolution of the STUN server.
void ResolveStunAddress();
void OnResolveResult(talk_base::SignalThread* thread);
void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
// Below methods handles binding request responses.
void OnStunBindingRequestSucceeded(const talk_base::SocketAddress& stun_addr);
@ -158,7 +160,7 @@ class UDPPort : public Port {
StunRequestManager requests_;
talk_base::AsyncPacketSocket* socket_;
int error_;
talk_base::AsyncResolver* resolver_;
talk_base::AsyncResolverInterface* resolver_;
bool ready_;
int stun_keepalive_delay_;

View File

@ -27,7 +27,10 @@
#include "talk/base/gunit.h"
#include "talk/base/helpers.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketaddress.h"
#include "talk/base/virtualsocketserver.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
#include "talk/p2p/base/stunport.h"
#include "talk/p2p/base/teststunserver.h"
@ -48,7 +51,10 @@ class StunPortTest : public testing::Test,
public sigslot::has_slots<> {
public:
StunPortTest()
: network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
: pss_(new talk_base::PhysicalSocketServer),
ss_(new talk_base::VirtualSocketServer(pss_.get())),
ss_scope_(ss_.get()),
network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32),
socket_factory_(talk_base::Thread::Current()),
stun_server_(new cricket::TestStunServer(
talk_base::Thread::Current(), kStunAddr)),
@ -77,7 +83,8 @@ class StunPortTest : public testing::Test,
ASSERT_TRUE(socket_ != NULL);
socket_->SignalReadPacket.connect(this, &StunPortTest::OnReadPacket);
stun_port_.reset(cricket::UDPPort::Create(
talk_base::Thread::Current(), &network_, socket_.get(),
talk_base::Thread::Current(), &socket_factory_,
&network_, socket_.get(),
talk_base::CreateRandomString(16), talk_base::CreateRandomString(22)));
ASSERT_TRUE(stun_port_ != NULL);
stun_port_->set_server_addr(server_addr);
@ -120,6 +127,9 @@ class StunPortTest : public testing::Test,
}
private:
talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_;
talk_base::scoped_ptr<talk_base::VirtualSocketServer> ss_;
talk_base::SocketServerScope ss_scope_;
talk_base::Network network_;
talk_base::BasicPacketSocketFactory socket_factory_;
talk_base::scoped_ptr<cricket::UDPPort> stun_port_;

View File

@ -399,22 +399,21 @@ void TurnPort::ResolveTurnAddress(const talk_base::SocketAddress& address) {
if (resolver_)
return;
resolver_ = new talk_base::AsyncResolver();
resolver_->SignalWorkDone.connect(this, &TurnPort::OnResolveResult);
resolver_->set_address(address);
resolver_->Start();
resolver_ = socket_factory()->CreateAsyncResolver();
resolver_->SignalDone.connect(this, &TurnPort::OnResolveResult);
resolver_->Start(address);
}
void TurnPort::OnResolveResult(talk_base::SignalThread* signal_thread) {
ASSERT(signal_thread == resolver_);
if (resolver_->error() != 0) {
void TurnPort::OnResolveResult(talk_base::AsyncResolverInterface* resolver) {
ASSERT(resolver == resolver_);
if (resolver_->GetError() != 0 ||
!resolver_->GetResolvedAddress(ip().family(), &server_address_.address)) {
LOG_J(LS_WARNING, this) << "TURN host lookup received error "
<< resolver_->error();
<< resolver_->GetError();
OnAllocateError();
return;
}
server_address_.address = resolver_->address();
PrepareAddress();
}

View File

@ -123,7 +123,7 @@ class TurnPort : public Port {
}
void ResolveTurnAddress(const talk_base::SocketAddress& address);
void OnResolveResult(talk_base::SignalThread* signal_thread);
void OnResolveResult(talk_base::AsyncResolverInterface* resolver);
void AddRequestAuthInfo(StunMessage* msg);
void OnSendStunPacket(const void* data, size_t size, StunRequest* request);
@ -157,7 +157,7 @@ class TurnPort : public Port {
talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_;
SocketOptionsMap socket_options_;
talk_base::AsyncResolver* resolver_;
talk_base::AsyncResolverInterface* resolver_;
int error_;
StunRequestManager request_manager_;

View File

@ -857,7 +857,8 @@ void AllocationSequence::CreateUDPPorts() {
// is enabled completely.
UDPPort* port = NULL;
if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
port = UDPPort::Create(session_->network_thread(), network_,
port = UDPPort::Create(session_->network_thread(),
session_->socket_factory(), network_,
udp_socket_.get(),
session_->username(), session_->password());
} else {