Implement GetState() for channel's connectivity check state.
Previously, IceState is considered completed when there is only one connection (and the rest was trimmed). However, since the trimming logic is only done within the scope of network, when IPv6 and IPv4 both exist, the completion event is never fired. This change adds the GetState() to each channel and it could decide what Completion means. The transport object then aggregates all channels before determining it's completed. Each channel's IceState will be aggregrated at Transport level for overall Ice state BUG=411086 R=pthatcher@webrtc.org Review URL: https://webrtc-codereview.appspot.com/30949004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7804 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
fd4acf6d55
commit
ff72f9e692
@ -109,9 +109,6 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
|
||||
virtual IceRole GetIceRole() const {
|
||||
return channel_->GetIceRole();
|
||||
}
|
||||
virtual size_t GetConnectionCount() const {
|
||||
return channel_->GetConnectionCount();
|
||||
}
|
||||
virtual bool SetLocalIdentity(rtc::SSLIdentity *identity);
|
||||
virtual bool GetLocalIdentity(rtc::SSLIdentity** identity) const;
|
||||
|
||||
@ -175,6 +172,10 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
|
||||
virtual Transport* GetTransport() {
|
||||
return transport_;
|
||||
}
|
||||
|
||||
virtual TransportChannelState GetState() const {
|
||||
return channel_->GetState();
|
||||
}
|
||||
virtual void SetIceTiebreaker(uint64 tiebreaker) {
|
||||
channel_->SetIceTiebreaker(tiebreaker);
|
||||
}
|
||||
|
@ -82,9 +82,20 @@ class FakeTransportChannel : public TransportChannelImpl,
|
||||
return transport_;
|
||||
}
|
||||
|
||||
virtual TransportChannelState GetState() const {
|
||||
if (connection_count_ == 0) {
|
||||
return TransportChannelState::STATE_FAILED;
|
||||
}
|
||||
|
||||
if (connection_count_ == 1) {
|
||||
return TransportChannelState::STATE_COMPLETED;
|
||||
}
|
||||
|
||||
return TransportChannelState::STATE_FAILED;
|
||||
}
|
||||
|
||||
virtual void SetIceRole(IceRole role) { role_ = role; }
|
||||
virtual IceRole GetIceRole() const { return role_; }
|
||||
virtual size_t GetConnectionCount() const { return connection_count_; }
|
||||
virtual void SetIceTiebreaker(uint64 tiebreaker) { tiebreaker_ = tiebreaker; }
|
||||
virtual bool GetIceProtocolType(IceProtocolType* type) const {
|
||||
*type = ice_proto_;
|
||||
|
@ -226,6 +226,36 @@ void P2PTransportChannel::SetIceTiebreaker(uint64 tiebreaker) {
|
||||
tiebreaker_ = tiebreaker;
|
||||
}
|
||||
|
||||
// Currently a channel is considered ICE completed once there is no
|
||||
// more than one connection per Network. This works for a single NIC
|
||||
// with both IPv4 and IPv6 enabled. However, this condition won't
|
||||
// happen when there are multiple NICs and all of them have
|
||||
// connectivity.
|
||||
// TODO(guoweis): Change Completion to be driven by a channel level
|
||||
// timer.
|
||||
TransportChannelState P2PTransportChannel::GetState() const {
|
||||
std::set<rtc::Network*> networks;
|
||||
|
||||
if (connections_.size() == 0) {
|
||||
return TransportChannelState::STATE_FAILED;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||
rtc::Network* network = connections_[i]->port()->Network();
|
||||
if (networks.find(network) == networks.end()) {
|
||||
networks.insert(network);
|
||||
} else {
|
||||
LOG_J(LS_VERBOSE, this) << "Ice not completed yet for this channel as "
|
||||
<< network->ToString()
|
||||
<< " has more than 1 connection.";
|
||||
return TransportChannelState::STATE_CONNECTING;
|
||||
}
|
||||
}
|
||||
LOG_J(LS_VERBOSE, this) << "Ice is completed for this channel.";
|
||||
|
||||
return TransportChannelState::STATE_COMPLETED;
|
||||
}
|
||||
|
||||
bool P2PTransportChannel::GetIceProtocolType(IceProtocolType* type) const {
|
||||
*type = protocol_type_;
|
||||
return true;
|
||||
@ -1065,7 +1095,7 @@ void P2PTransportChannel::HandleAllTimedOut() {
|
||||
// If we have a best connection, return it, otherwise return top one in the
|
||||
// list (later we will mark it best).
|
||||
Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
|
||||
rtc::Network* network) {
|
||||
rtc::Network* network) const {
|
||||
// If the best connection is on this network, then it wins.
|
||||
if (best_connection_ && (best_connection_->port()->Network() == network))
|
||||
return best_connection_;
|
||||
|
@ -59,10 +59,10 @@ class P2PTransportChannel : public TransportChannelImpl,
|
||||
|
||||
// From TransportChannelImpl:
|
||||
virtual Transport* GetTransport() { return transport_; }
|
||||
virtual TransportChannelState GetState() const;
|
||||
virtual void SetIceRole(IceRole role);
|
||||
virtual IceRole GetIceRole() const { return ice_role_; }
|
||||
virtual void SetIceTiebreaker(uint64 tiebreaker);
|
||||
virtual size_t GetConnectionCount() const { return connections_.size(); }
|
||||
virtual bool GetIceProtocolType(IceProtocolType* type) const;
|
||||
virtual void SetIceProtocolType(IceProtocolType type);
|
||||
virtual void SetIceCredentials(const std::string& ice_ufrag,
|
||||
@ -164,7 +164,7 @@ class P2PTransportChannel : public TransportChannelImpl,
|
||||
void HandleNotWritable();
|
||||
void HandleAllTimedOut();
|
||||
|
||||
Connection* GetBestConnectionOnNetwork(rtc::Network* network);
|
||||
Connection* GetBestConnectionOnNetwork(rtc::Network* network) const;
|
||||
bool CreateConnections(const Candidate &remote_candidate,
|
||||
PortInterface* origin_port, bool readable);
|
||||
bool CreateConnection(PortInterface* port, const Candidate& remote_candidate,
|
||||
|
@ -927,7 +927,8 @@ void Connection::set_write_state(WriteState value) {
|
||||
WriteState old_value = write_state_;
|
||||
write_state_ = value;
|
||||
if (value != old_value) {
|
||||
LOG_J(LS_VERBOSE, this) << "set_write_state";
|
||||
LOG_J(LS_VERBOSE, this) << "set_write_state from: " << old_value << " to "
|
||||
<< value;
|
||||
SignalStateChange(this);
|
||||
CheckTimeout();
|
||||
}
|
||||
@ -1102,8 +1103,10 @@ void Connection::UpdateState(uint32 now) {
|
||||
pings_since_last_response_[i]);
|
||||
pings.append(buf).append(" ");
|
||||
}
|
||||
LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_=" <<
|
||||
pings << ", rtt=" << rtt << ", now=" << now;
|
||||
LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_="
|
||||
<< pings << ", rtt=" << rtt << ", now=" << now
|
||||
<< ", last ping received: " << last_ping_received_
|
||||
<< ", last data_received: " << last_data_received_;
|
||||
|
||||
// Check the readable state.
|
||||
//
|
||||
@ -1187,6 +1190,12 @@ void Connection::ReceivedPing() {
|
||||
set_read_state(STATE_READABLE);
|
||||
}
|
||||
|
||||
std::string Connection::ToDebugId() const {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string Connection::ToString() const {
|
||||
const char CONNECT_STATE_ABBREV[2] = {
|
||||
'-', // not connected (false)
|
||||
@ -1212,7 +1221,8 @@ std::string Connection::ToString() const {
|
||||
const Candidate& local = local_candidate();
|
||||
const Candidate& remote = remote_candidate();
|
||||
std::stringstream ss;
|
||||
ss << "Conn[" << port_->content_name()
|
||||
ss << "Conn[" << ToDebugId()
|
||||
<< ":" << port_->content_name()
|
||||
<< ":" << local.id() << ":" << local.component()
|
||||
<< ":" << local.generation()
|
||||
<< ":" << local.type() << ":" << local.protocol()
|
||||
|
@ -517,6 +517,7 @@ class Connection : public rtc::MessageHandler,
|
||||
void ReceivedPing();
|
||||
|
||||
// Debugging description of this connection
|
||||
std::string ToDebugId() const;
|
||||
std::string ToString() const;
|
||||
std::string ToSensitiveString() const;
|
||||
|
||||
|
@ -54,6 +54,9 @@ class RawTransportChannel : public TransportChannelImpl,
|
||||
|
||||
// Implements TransportChannelImpl.
|
||||
virtual Transport* GetTransport() { return raw_transport_; }
|
||||
virtual TransportChannelState GetState() const {
|
||||
return TransportChannelState::STATE_COMPLETED;
|
||||
}
|
||||
virtual void SetIceCredentials(const std::string& ice_ufrag,
|
||||
const std::string& ice_pwd) {}
|
||||
virtual void SetRemoteIceCredentials(const std::string& ice_ufrag,
|
||||
|
@ -669,8 +669,7 @@ void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t connections = channel->GetConnectionCount();
|
||||
if (connections == 0) {
|
||||
if (channel->GetState() == TransportChannelState::STATE_FAILED) {
|
||||
// A Transport has failed if any of its channels have no remaining
|
||||
// connections.
|
||||
signaling_thread_->Post(this, MSG_FAILED);
|
||||
@ -680,6 +679,12 @@ void Transport::OnChannelConnectionRemoved(TransportChannelImpl* channel) {
|
||||
void Transport::MaybeCompleted_w() {
|
||||
ASSERT(worker_thread()->IsCurrent());
|
||||
|
||||
// When there is no channel created yet, calling this function could fire an
|
||||
// IceConnectionCompleted event prematurely.
|
||||
if (channels_.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A Transport's ICE process is completed if all of its channels are writable,
|
||||
// have finished allocating candidates, and have pruned all but one of their
|
||||
// connections.
|
||||
@ -687,7 +692,7 @@ void Transport::MaybeCompleted_w() {
|
||||
for (iter = channels_.begin(); iter != channels_.end(); ++iter) {
|
||||
const TransportChannelImpl* channel = iter->second.get();
|
||||
if (!(channel->writable() &&
|
||||
channel->GetConnectionCount() == 1 &&
|
||||
channel->GetState() == TransportChannelState::STATE_COMPLETED &&
|
||||
channel->GetIceRole() == ICEROLE_CONTROLLING &&
|
||||
iter->second.candidates_allocated())) {
|
||||
return;
|
||||
|
@ -36,6 +36,9 @@ enum PacketFlags {
|
||||
// crypto provided by the transport (e.g. DTLS)
|
||||
};
|
||||
|
||||
// Used to indicate channel's connection state.
|
||||
enum TransportChannelState { STATE_CONNECTING, STATE_COMPLETED, STATE_FAILED };
|
||||
|
||||
// A TransportChannel represents one logical stream of packets that are sent
|
||||
// between the two sides of a session.
|
||||
class TransportChannel : public sigslot::has_slots<> {
|
||||
@ -46,6 +49,8 @@ class TransportChannel : public sigslot::has_slots<> {
|
||||
readable_(false), writable_(false) {}
|
||||
virtual ~TransportChannel() {}
|
||||
|
||||
virtual TransportChannelState GetState() const = 0;
|
||||
|
||||
// TODO(mallinath) - Remove this API, as it's no longer useful.
|
||||
// Returns the session id of this channel.
|
||||
virtual const std::string SessionId() const { return std::string(); }
|
||||
|
@ -36,7 +36,6 @@ class TransportChannelImpl : public TransportChannel {
|
||||
virtual IceRole GetIceRole() const = 0;
|
||||
virtual void SetIceRole(IceRole role) = 0;
|
||||
virtual void SetIceTiebreaker(uint64 tiebreaker) = 0;
|
||||
virtual size_t GetConnectionCount() const = 0;
|
||||
// To toggle G-ICE/ICE.
|
||||
virtual bool GetIceProtocolType(IceProtocolType* type) const = 0;
|
||||
virtual void SetIceProtocolType(IceProtocolType type) = 0;
|
||||
|
@ -111,6 +111,14 @@ int TransportChannelProxy::GetError() {
|
||||
return impl_->GetError();
|
||||
}
|
||||
|
||||
TransportChannelState TransportChannelProxy::GetState() const {
|
||||
ASSERT(rtc::Thread::Current() == worker_thread_);
|
||||
if (!impl_) {
|
||||
return TransportChannelState::STATE_CONNECTING;
|
||||
}
|
||||
return impl_->GetState();
|
||||
}
|
||||
|
||||
bool TransportChannelProxy::GetStats(ConnectionInfos* infos) {
|
||||
ASSERT(rtc::Thread::Current() == worker_thread_);
|
||||
if (!impl_) {
|
||||
|
@ -41,6 +41,8 @@ class TransportChannelProxy : public TransportChannel,
|
||||
const std::string& name() const { return name_; }
|
||||
TransportChannelImpl* impl() { return impl_; }
|
||||
|
||||
virtual TransportChannelState GetState() const;
|
||||
|
||||
// Sets the implementation to which we will proxy.
|
||||
void SetImplementation(TransportChannelImpl* impl);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user