Add 16-bit network id to the candidate signaling.
Also include that in the stun-ping request as part of the network-info attribute. Change the network cost to be 16 bits. BUG= Review URL: https://codereview.webrtc.org/1815473002 Cr-Commit-Position: refs/heads/master@{#12110}
This commit is contained in:
parent
887a19b9d2
commit
a0c44eaa82
@ -127,6 +127,7 @@ static const char kAttributeCandidateRport[] = "rport";
|
||||
static const char kAttributeCandidateUfrag[] = "ufrag";
|
||||
static const char kAttributeCandidatePwd[] = "pwd";
|
||||
static const char kAttributeCandidateGeneration[] = "generation";
|
||||
static const char kAttributeCandidateNetworkId[] = "network-id";
|
||||
static const char kAttributeCandidateNetworkCost[] = "network-cost";
|
||||
static const char kAttributeFingerprint[] = "fingerprint";
|
||||
static const char kAttributeSetup[] = "setup";
|
||||
@ -1092,7 +1093,8 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
|
||||
std::string username;
|
||||
std::string password;
|
||||
uint32_t generation = 0;
|
||||
uint32_t network_cost = 0;
|
||||
uint16_t network_id = 0;
|
||||
uint16_t network_cost = 0;
|
||||
for (size_t i = current_position; i + 1 < fields.size(); ++i) {
|
||||
// RFC 5245
|
||||
// *(SP extension-att-name SP extension-att-value)
|
||||
@ -1104,10 +1106,15 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
|
||||
username = fields[++i];
|
||||
} else if (fields[i] == kAttributeCandidatePwd) {
|
||||
password = fields[++i];
|
||||
} else if (fields[i] == kAttributeCandidateNetworkId) {
|
||||
if (!GetValueFromString(first_line, fields[++i], &network_id, error)) {
|
||||
return false;
|
||||
}
|
||||
} else if (fields[i] == kAttributeCandidateNetworkCost) {
|
||||
if (!GetValueFromString(first_line, fields[++i], &network_cost, error)) {
|
||||
return false;
|
||||
}
|
||||
network_cost = std::min(network_cost, cricket::kMaxNetworkCost);
|
||||
} else {
|
||||
// Skip the unknown extension.
|
||||
++i;
|
||||
@ -1116,10 +1123,9 @@ bool ParseCandidate(const std::string& message, Candidate* candidate,
|
||||
|
||||
*candidate = Candidate(component_id, cricket::ProtoToString(protocol),
|
||||
address, priority, username, password, candidate_type,
|
||||
generation, foundation);
|
||||
generation, foundation, network_id, network_cost);
|
||||
candidate->set_related_address(related_address);
|
||||
candidate->set_tcptype(tcptype);
|
||||
candidate->set_network_cost(std::min(network_cost, cricket::kMaxNetworkCost));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1814,6 +1820,9 @@ void BuildCandidate(const std::vector<Candidate>& candidates,
|
||||
if (include_ufrag && !it->username().empty()) {
|
||||
os << " " << kAttributeCandidateUfrag << " " << it->username();
|
||||
}
|
||||
if (it->network_id() > 0) {
|
||||
os << " " << kAttributeCandidateNetworkId << " " << it->network_id();
|
||||
}
|
||||
if (it->network_cost() > 0) {
|
||||
os << " " << kAttributeCandidateNetworkCost << " " << it->network_cost();
|
||||
}
|
||||
|
||||
@ -2058,6 +2058,19 @@ TEST_F(WebRtcSdpTest, SerializeCandidates) {
|
||||
candidate_with_ufrag));
|
||||
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
||||
EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
|
||||
|
||||
Candidate candidate_with_network_info(candidates_.front());
|
||||
candidate_with_network_info.set_network_id(1);
|
||||
jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
|
||||
candidate_with_network_info));
|
||||
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
||||
EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
|
||||
candidate_with_network_info.set_network_cost(999);
|
||||
jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
|
||||
candidate_with_network_info));
|
||||
message = webrtc::SdpSerializeCandidate(*jcandidate_);
|
||||
EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
|
||||
message);
|
||||
}
|
||||
|
||||
// TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing
|
||||
@ -2325,6 +2338,7 @@ TEST_F(WebRtcSdpTest, DeserializeCandidate) {
|
||||
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
||||
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
||||
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
|
||||
EXPECT_EQ(0, jcandidate.candidate().network_cost());
|
||||
|
||||
// Candidate line without generation extension.
|
||||
sdp = kSdpOneCandidate;
|
||||
@ -2336,6 +2350,22 @@ TEST_F(WebRtcSdpTest, DeserializeCandidate) {
|
||||
expected.set_generation(0);
|
||||
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
||||
|
||||
// Candidate with network id and/or cost.
|
||||
sdp = kSdpOneCandidate;
|
||||
Replace(" generation 2", " generation 2 network-id 2", &sdp);
|
||||
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
||||
EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
|
||||
EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
|
||||
expected = jcandidate_->candidate();
|
||||
expected.set_network_id(2);
|
||||
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
||||
EXPECT_EQ(0, jcandidate.candidate().network_cost());
|
||||
// Add network cost
|
||||
Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
|
||||
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
||||
EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
|
||||
EXPECT_EQ(9, jcandidate.candidate().network_cost());
|
||||
|
||||
sdp = kSdpTcpActiveCandidate;
|
||||
EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
|
||||
// Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
|
||||
|
||||
@ -286,6 +286,7 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
|
||||
// This network is new. Place it in the network map.
|
||||
merged_list.push_back(net);
|
||||
networks_map_[key] = net;
|
||||
net->set_id(next_available_network_id_++);
|
||||
// Also, we might have accumulated IPAddresses from the first
|
||||
// step, set it here.
|
||||
net->SetIPs(kv.second.ips, true);
|
||||
|
||||
@ -173,6 +173,11 @@ class NetworkManagerBase : public NetworkManager {
|
||||
|
||||
IPAddress default_local_ipv4_address_;
|
||||
IPAddress default_local_ipv6_address_;
|
||||
// We use 16 bits to save the bandwidth consumption when sending the network
|
||||
// id over the Internet. It is OK that the 16-bit integer overflows to get a
|
||||
// network id 0 because we only compare the network ids in the old and the new
|
||||
// best connections in the transport channel.
|
||||
uint16_t next_available_network_id_ = 1;
|
||||
};
|
||||
|
||||
// Basic implementation of the NetworkManager interface that gets list
|
||||
@ -339,6 +344,11 @@ class Network {
|
||||
AdapterType type() const { return type_; }
|
||||
void set_type(AdapterType type) { type_ = type; }
|
||||
|
||||
// A unique id assigned by the network manager, which may be signaled
|
||||
// to the remote side in the candidate.
|
||||
uint16_t id() const { return id_; }
|
||||
void set_id(uint16_t id) { id_ = id; }
|
||||
|
||||
int preference() const { return preference_; }
|
||||
void set_preference(int preference) { preference_ = preference; }
|
||||
|
||||
@ -372,6 +382,7 @@ class Network {
|
||||
AdapterType type_;
|
||||
int preference_;
|
||||
bool active_ = true;
|
||||
uint16_t id_ = 0;
|
||||
|
||||
friend class NetworkManager;
|
||||
};
|
||||
|
||||
@ -299,6 +299,8 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) {
|
||||
EXPECT_EQ(1U, list.size());
|
||||
EXPECT_EQ(ipv4_network1.ToString(), list[0]->ToString());
|
||||
Network* net1 = list[0];
|
||||
uint16_t net_id1 = net1->id();
|
||||
EXPECT_EQ(1, net_id1);
|
||||
list.clear();
|
||||
|
||||
// Replace ipv4_network1 with ipv4_network2.
|
||||
@ -315,6 +317,9 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) {
|
||||
EXPECT_EQ(1U, list.size());
|
||||
EXPECT_EQ(ipv4_network2.ToString(), list[0]->ToString());
|
||||
Network* net2 = list[0];
|
||||
uint16_t net_id2 = net2->id();
|
||||
// Network id will increase.
|
||||
EXPECT_LT(net_id1, net_id2);
|
||||
list.clear();
|
||||
|
||||
// Add Network2 back.
|
||||
@ -332,6 +337,8 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) {
|
||||
EXPECT_EQ(2U, list.size());
|
||||
EXPECT_TRUE((net1 == list[0] && net2 == list[1]) ||
|
||||
(net1 == list[1] && net2 == list[0]));
|
||||
EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
|
||||
(net_id1 == list[1]->id() && net_id2 == list[0]->id()));
|
||||
list.clear();
|
||||
|
||||
// Call MergeNetworkList() again and verify that we don't get update
|
||||
@ -350,6 +357,8 @@ TEST_F(NetworkTest, TestBasicMergeNetworkList) {
|
||||
EXPECT_EQ(2U, list.size());
|
||||
EXPECT_TRUE((net1 == list[0] && net2 == list[1]) ||
|
||||
(net1 == list[1] && net2 == list[0]));
|
||||
EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
|
||||
(net_id1 == list[1]->id() && net_id2 == list[0]->id()));
|
||||
list.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ class NetworkBinderInterface {
|
||||
// This is needed because some operating systems (like Android) require a
|
||||
// special bind call to put packets on a non-default network interface.
|
||||
virtual int BindSocketToNetwork(int socket_fd, const IPAddress& address) = 0;
|
||||
virtual ~NetworkBinderInterface() {}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
namespace cricket {
|
||||
|
||||
const uint32_t kMaxNetworkCost = 999;
|
||||
const uint16_t kMaxNetworkCost = 999;
|
||||
|
||||
// Candidate for ICE based connection discovery.
|
||||
|
||||
@ -40,7 +40,9 @@ class Candidate {
|
||||
component_(0),
|
||||
priority_(0),
|
||||
network_type_(rtc::ADAPTER_TYPE_UNKNOWN),
|
||||
generation_(0) {}
|
||||
generation_(0),
|
||||
network_id_(0),
|
||||
network_cost_(0) {}
|
||||
|
||||
Candidate(int component,
|
||||
const std::string& protocol,
|
||||
@ -50,7 +52,9 @@ class Candidate {
|
||||
const std::string& password,
|
||||
const std::string& type,
|
||||
uint32_t generation,
|
||||
const std::string& foundation)
|
||||
const std::string& foundation,
|
||||
uint16_t network_id = 0,
|
||||
uint16_t network_cost = 0)
|
||||
: id_(rtc::CreateRandomString(8)),
|
||||
component_(component),
|
||||
protocol_(protocol),
|
||||
@ -61,7 +65,9 @@ class Candidate {
|
||||
type_(type),
|
||||
network_type_(rtc::ADAPTER_TYPE_UNKNOWN),
|
||||
generation_(generation),
|
||||
foundation_(foundation) {}
|
||||
foundation_(foundation),
|
||||
network_id_(network_id),
|
||||
network_cost_(network_cost) {}
|
||||
|
||||
const std::string & id() const { return id_; }
|
||||
void set_id(const std::string & id) { id_ = id; }
|
||||
@ -143,11 +149,15 @@ class Candidate {
|
||||
// |network_cost| measures the cost/penalty of using this candidate. A network
|
||||
// cost of 0 indicates this candidate can be used freely. A value of
|
||||
// |kMaxNetworkCost| indicates it should be used only as the last resort.
|
||||
void set_network_cost(uint32_t network_cost) {
|
||||
void set_network_cost(uint16_t network_cost) {
|
||||
ASSERT(network_cost <= kMaxNetworkCost);
|
||||
network_cost_ = network_cost;
|
||||
}
|
||||
uint32_t network_cost() const { return network_cost_; }
|
||||
uint16_t network_cost() const { return network_cost_; }
|
||||
|
||||
// An ID assigned to the network hosting the candidate.
|
||||
uint16_t network_id() const { return network_id_; }
|
||||
void set_network_id(uint16_t network_id) { network_id_ = network_id; }
|
||||
|
||||
const std::string& foundation() const {
|
||||
return foundation_;
|
||||
@ -178,13 +188,14 @@ class Candidate {
|
||||
// Determines whether this candidate is equivalent to the given one.
|
||||
bool IsEquivalent(const Candidate& c) const {
|
||||
// We ignore the network name, since that is just debug information, and
|
||||
// the priority, since that should be the same if the rest is (and it's
|
||||
// a float so equality checking is always worrisome).
|
||||
// the priority and the network cost, since they should be the same if the
|
||||
// rest are.
|
||||
return (component_ == c.component_) && (protocol_ == c.protocol_) &&
|
||||
(address_ == c.address_) && (username_ == c.username_) &&
|
||||
(password_ == c.password_) && (type_ == c.type_) &&
|
||||
(generation_ == c.generation_) && (foundation_ == c.foundation_) &&
|
||||
(related_address_ == c.related_address_);
|
||||
(related_address_ == c.related_address_) &&
|
||||
(network_id_ == c.network_id_);
|
||||
}
|
||||
|
||||
// Determines whether this candidate can be considered equivalent to the
|
||||
@ -238,7 +249,7 @@ class Candidate {
|
||||
ost << "Cand[" << transport_name_ << ":" << foundation_ << ":" << component_
|
||||
<< ":" << protocol_ << ":" << priority_ << ":" << address << ":"
|
||||
<< type_ << ":" << related_address_ << ":" << username_ << ":"
|
||||
<< password_ << ":" << network_cost_ << "]";
|
||||
<< password_ << ":" << network_id_ << ":" << network_cost_ << "]";
|
||||
return ost.str();
|
||||
}
|
||||
|
||||
@ -257,8 +268,9 @@ class Candidate {
|
||||
std::string foundation_;
|
||||
rtc::SocketAddress related_address_;
|
||||
std::string tcptype_;
|
||||
uint32_t network_cost_ = 0;
|
||||
std::string transport_name_;
|
||||
uint16_t network_id_;
|
||||
uint16_t network_cost_;
|
||||
};
|
||||
|
||||
// Used during parsing and writing to map component to channel name
|
||||
|
||||
@ -614,25 +614,30 @@ void P2PTransportChannel::OnUnknownAddress(
|
||||
}
|
||||
int remote_candidate_priority = priority_attr->value();
|
||||
|
||||
const StunUInt32Attribute* cost_attr =
|
||||
stun_msg->GetUInt32(STUN_ATTR_NETWORK_COST);
|
||||
uint32_t network_cost = (cost_attr) ? cost_attr->value() : 0;
|
||||
uint16_t network_id = 0;
|
||||
uint16_t network_cost = 0;
|
||||
const StunUInt32Attribute* network_attr =
|
||||
stun_msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
|
||||
if (network_attr) {
|
||||
uint32_t network_info = network_attr->value();
|
||||
network_id = static_cast<uint16_t>(network_info >> 16);
|
||||
network_cost = static_cast<uint16_t>(network_info);
|
||||
}
|
||||
|
||||
// RFC 5245
|
||||
// If the source transport address of the request does not match any
|
||||
// existing remote candidates, it represents a new peer reflexive remote
|
||||
// candidate.
|
||||
remote_candidate = Candidate(component(), ProtoToString(proto), address, 0,
|
||||
remote_username, remote_password,
|
||||
PRFLX_PORT_TYPE, remote_generation, "");
|
||||
remote_candidate = Candidate(
|
||||
component(), ProtoToString(proto), address, remote_candidate_priority,
|
||||
remote_username, remote_password, PRFLX_PORT_TYPE, remote_generation,
|
||||
"", network_id, network_cost);
|
||||
|
||||
// From RFC 5245, section-7.2.1.3:
|
||||
// The foundation of the candidate is set to an arbitrary value, different
|
||||
// from the foundation for all other remote candidates.
|
||||
remote_candidate.set_foundation(
|
||||
rtc::ToString<uint32_t>(rtc::ComputeCrc32(remote_candidate.id())));
|
||||
remote_candidate.set_priority(remote_candidate_priority);
|
||||
remote_candidate.set_network_cost(network_cost);
|
||||
}
|
||||
|
||||
// RFC5245, the agent constructs a pair whose local candidate is equal to
|
||||
|
||||
@ -242,25 +242,17 @@ void Port::AddAddress(const rtc::SocketAddress& address,
|
||||
ASSERT(!tcptype.empty());
|
||||
}
|
||||
|
||||
Candidate c;
|
||||
c.set_id(rtc::CreateRandomString(8));
|
||||
c.set_component(component_);
|
||||
c.set_type(type);
|
||||
c.set_protocol(protocol);
|
||||
std::string foundation =
|
||||
ComputeFoundation(type, protocol, relay_protocol, base_address);
|
||||
Candidate c(component_, protocol, address, 0U, username_fragment(), password_,
|
||||
type, generation_, foundation, network_->id(), network_cost_);
|
||||
c.set_priority(
|
||||
c.GetPriority(type_preference, network_->preference(), relay_preference));
|
||||
c.set_relay_protocol(relay_protocol);
|
||||
c.set_tcptype(tcptype);
|
||||
c.set_address(address);
|
||||
c.set_priority(c.GetPriority(type_preference, network_->preference(),
|
||||
relay_preference));
|
||||
c.set_username(username_fragment());
|
||||
c.set_password(password_);
|
||||
c.set_network_name(network_->name());
|
||||
c.set_network_type(network_->type());
|
||||
c.set_network_cost(network_cost_);
|
||||
c.set_generation(generation_);
|
||||
c.set_related_address(related_address);
|
||||
c.set_foundation(
|
||||
ComputeFoundation(type, protocol, relay_protocol, base_address));
|
||||
candidates_.push_back(c);
|
||||
SignalCandidateReady(this, c);
|
||||
|
||||
@ -705,11 +697,10 @@ class ConnectionRequest : public StunRequest {
|
||||
static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
|
||||
1)));
|
||||
}
|
||||
uint32_t network_cost = connection_->port()->network_cost();
|
||||
if (network_cost > 0) {
|
||||
uint32_t network_info = connection_->port()->Network()->id();
|
||||
network_info = (network_info << 16) | connection_->port()->network_cost();
|
||||
request->AddAttribute(
|
||||
new StunUInt32Attribute(STUN_ATTR_NETWORK_COST, network_cost));
|
||||
}
|
||||
new StunUInt32Attribute(STUN_ATTR_NETWORK_INFO, network_info));
|
||||
|
||||
// Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
|
||||
if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
|
||||
@ -1412,11 +1403,12 @@ void Connection::MaybeAddPrflxCandidate(ConnectionRequest* request,
|
||||
new_local_candidate.set_password(local_candidate().password());
|
||||
new_local_candidate.set_network_name(local_candidate().network_name());
|
||||
new_local_candidate.set_network_type(local_candidate().network_type());
|
||||
new_local_candidate.set_network_cost(local_candidate().network_cost());
|
||||
new_local_candidate.set_related_address(local_candidate().address());
|
||||
new_local_candidate.set_foundation(ComputeFoundation(
|
||||
PRFLX_PORT_TYPE, local_candidate().protocol(),
|
||||
local_candidate().relay_protocol(), local_candidate().address()));
|
||||
new_local_candidate.set_network_id(local_candidate().network_id());
|
||||
new_local_candidate.set_network_cost(local_candidate().network_cost());
|
||||
|
||||
// Change the local candidate of this Connection to the new prflx candidate.
|
||||
local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
|
||||
|
||||
@ -296,7 +296,7 @@ class Port : public PortInterface, public rtc::MessageHandler,
|
||||
void set_candidate_filter(uint32_t candidate_filter) {
|
||||
candidate_filter_ = candidate_filter;
|
||||
}
|
||||
int32_t network_cost() const { return network_cost_; }
|
||||
int16_t network_cost() const { return network_cost_; }
|
||||
|
||||
protected:
|
||||
enum {
|
||||
@ -403,7 +403,7 @@ class Port : public PortInterface, public rtc::MessageHandler,
|
||||
// A virtual cost perceived by the user, usually based on the network type
|
||||
// (WiFi. vs. Cellular). It takes precedence over the priority when
|
||||
// comparing two connections.
|
||||
uint32_t network_cost_;
|
||||
uint16_t network_cost_;
|
||||
|
||||
friend class Connection;
|
||||
};
|
||||
|
||||
@ -559,6 +559,10 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
|
||||
}
|
||||
}
|
||||
|
||||
void SetNetworkType(rtc::AdapterType adapter_type) {
|
||||
network_.set_type(adapter_type);
|
||||
}
|
||||
|
||||
void TestCrossFamilyPorts(int type);
|
||||
|
||||
void ExpectPortsCanConnect(bool can_connect, Port* p1, Port* p2);
|
||||
@ -1757,6 +1761,51 @@ TEST_F(PortTest, TestUseCandidateAttribute) {
|
||||
ASSERT_TRUE(use_candidate_attr != NULL);
|
||||
}
|
||||
|
||||
TEST_F(PortTest, TestNetworkInfoAttribute) {
|
||||
rtc::scoped_ptr<TestPort> lport(
|
||||
CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
|
||||
// Set the network type for rport to be cellular so its cost will be 999.
|
||||
SetNetworkType(rtc::ADAPTER_TYPE_CELLULAR);
|
||||
rtc::scoped_ptr<TestPort> rport(
|
||||
CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
|
||||
lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
|
||||
lport->SetIceTiebreaker(kTiebreaker1);
|
||||
rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
|
||||
rport->SetIceTiebreaker(kTiebreaker2);
|
||||
|
||||
uint16_t lnetwork_id = 9;
|
||||
lport->Network()->set_id(lnetwork_id);
|
||||
// Send a fake ping from lport to rport.
|
||||
lport->PrepareAddress();
|
||||
rport->PrepareAddress();
|
||||
Connection* lconn =
|
||||
lport->CreateConnection(rport->Candidates()[0], Port::ORIGIN_MESSAGE);
|
||||
lconn->Ping(0);
|
||||
ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
|
||||
IceMessage* msg = lport->last_stun_msg();
|
||||
const StunUInt32Attribute* network_info_attr =
|
||||
msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
|
||||
ASSERT_TRUE(network_info_attr != NULL);
|
||||
uint32_t network_info = network_info_attr->value();
|
||||
EXPECT_EQ(lnetwork_id, network_info >> 16);
|
||||
// Default network cost is 0.
|
||||
EXPECT_EQ(0U, network_info & 0xFFFF);
|
||||
|
||||
// Send a fake ping from rport to lport.
|
||||
uint16_t rnetwork_id = 8;
|
||||
rport->Network()->set_id(rnetwork_id);
|
||||
Connection* rconn =
|
||||
rport->CreateConnection(lport->Candidates()[0], Port::ORIGIN_MESSAGE);
|
||||
rconn->Ping(0);
|
||||
ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000);
|
||||
msg = rport->last_stun_msg();
|
||||
network_info_attr = msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
|
||||
ASSERT_TRUE(network_info_attr != NULL);
|
||||
network_info = network_info_attr->value();
|
||||
EXPECT_EQ(rnetwork_id, network_info >> 16);
|
||||
EXPECT_EQ(cricket::kMaxNetworkCost, network_info & 0xFFFF);
|
||||
}
|
||||
|
||||
// Test handling STUN messages.
|
||||
TEST_F(PortTest, TestHandleStunMessage) {
|
||||
// Our port will act as the "remote" port.
|
||||
|
||||
@ -606,7 +606,9 @@ enum IceAttributeType {
|
||||
STUN_ATTR_USE_CANDIDATE = 0x0025, // No content, Length = 0
|
||||
STUN_ATTR_ICE_CONTROLLED = 0x8029, // UInt64
|
||||
STUN_ATTR_ICE_CONTROLLING = 0x802A, // UInt64
|
||||
STUN_ATTR_NETWORK_COST = 0xC057 // UInt32
|
||||
// UInt32. The higher 16 bits are the network ID. The lower 16 bits are the
|
||||
// network cost.
|
||||
STUN_ATTR_NETWORK_INFO = 0xC057
|
||||
};
|
||||
|
||||
// RFC 5245-defined errors.
|
||||
@ -621,7 +623,7 @@ class IceMessage : public StunMessage {
|
||||
virtual StunAttributeValueType GetAttributeValueType(int type) const {
|
||||
switch (type) {
|
||||
case STUN_ATTR_PRIORITY:
|
||||
case STUN_ATTR_NETWORK_COST:
|
||||
case STUN_ATTR_NETWORK_INFO:
|
||||
return STUN_VALUE_UINT32;
|
||||
case STUN_ATTR_USE_CANDIDATE: return STUN_VALUE_BYTE_STRING;
|
||||
case STUN_ATTR_ICE_CONTROLLED: return STUN_VALUE_UINT64;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user