Commit 915c6928 authored by Derek Cheng's avatar Derek Cheng Committed by Commit Bot

[CastMRP] Fix a couple of bugs in CMSSImpl.

- On channel error, erase the sink from |current_sinks_map|.
  crrev.com/541271 added a check in OpenChannel() to short circuit if
  a sink already exists on the map. In order for retry on error to kick
  in properly, we will need to erase the entry in OnError().
- In OnChannelOpenSucceeded, erase stale sink with the same IP. This is
  done to maintain the invariant of having at most 1 sink of a given ID
  in the map. Stale sink is defined as having the same sink ID but
  different IP endpoint than the current one.
- In OnChannelOpenFailed, when erasing the sink from
  |current_sinks_map_|, also verify the sink ID. It is possible that
  a different sink now occcupies the IP endpoint that it is trying to
  erase.

Change-Id: I12bfd5af5f664c4773e7587dc30c6709d2352021
Bug: 698940
Reviewed-on: https://chromium-review.googlesource.com/961555Reviewed-by: default avatarBin Zhao <zhaobin@chromium.org>
Commit-Queue: Derek Cheng <imcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543439}
parent 82b329f0
...@@ -350,6 +350,16 @@ void CastMediaSinkServiceImpl::OnError(const cast_channel::CastSocket& socket, ...@@ -350,6 +350,16 @@ void CastMediaSinkServiceImpl::OnError(const cast_channel::CastSocket& socket,
base::BindOnce(&CastMediaSinkServiceImpl::OpenChannel, GetWeakPtr(), base::BindOnce(&CastMediaSinkServiceImpl::OpenChannel, GetWeakPtr(),
ip_endpoint, cast_sink_it->second, nullptr, ip_endpoint, cast_sink_it->second, nullptr,
SinkSource::kConnectionRetry)); SinkSource::kConnectionRetry));
// We erase the sink here so that OpenChannel would not find an existing
// sink.
// Note: a better longer term solution is to introduce a state field to the
// sink. We would set it to ERROR here. In OpenChannel(), we would check
// create a socket only if the state is not already CONNECTED.
if (observer_)
observer_->OnSinkRemoved(cast_sink_it->second);
current_sinks_map_.erase(cast_sink_it);
MediaSinkServiceBase::RestartTimer();
return; return;
} }
...@@ -382,6 +392,9 @@ void CastMediaSinkServiceImpl::OnNetworksChanged( ...@@ -382,6 +392,9 @@ void CastMediaSinkServiceImpl::OnNetworksChanged(
} }
sink_cache_[last_network_id] = std::move(current_sinks); sink_cache_[last_network_id] = std::move(current_sinks);
} }
// TODO(imcheng): Maybe this should clear |current_sinks_map_| and call
// |RestartTimer()| so it is more responsive?
if (IsNetworkIdUnknownOrDisconnected(network_id)) if (IsNetworkIdUnknownOrDisconnected(network_id))
return; return;
...@@ -511,7 +524,7 @@ void CastMediaSinkServiceImpl::OnChannelErrorMayRetry( ...@@ -511,7 +524,7 @@ void CastMediaSinkServiceImpl::OnChannelErrorMayRetry(
<< ip_endpoint.ToString() << " [error_state]: " << ip_endpoint.ToString() << " [error_state]: "
<< cast_channel::ChannelErrorToString(error_state); << cast_channel::ChannelErrorToString(error_state);
OnChannelOpenFailed(ip_endpoint); OnChannelOpenFailed(ip_endpoint, cast_sink);
CastAnalytics::RecordCastChannelConnectResult( CastAnalytics::RecordCastChannelConnectResult(
MediaRouterChannelConnectResults::FAILURE); MediaRouterChannelConnectResults::FAILURE);
return; return;
...@@ -572,6 +585,18 @@ void CastMediaSinkServiceImpl::OnChannelOpenSucceeded( ...@@ -572,6 +585,18 @@ void CastMediaSinkServiceImpl::OnChannelOpenSucceeded(
sink_it->second = cast_sink; sink_it->second = cast_sink;
} }
// If the sink was under a different IP address previously, remove it from
// |current_sinks_map_|.
auto old_sink_it = std::find_if(
current_sinks_map_.begin(), current_sinks_map_.end(),
[&cast_sink, &ip_endpoint](
const std::pair<net::IPEndPoint, MediaSinkInternal>& entry) {
return !(entry.first == ip_endpoint) &&
entry.second.sink().id() == cast_sink.sink().id();
});
if (old_sink_it != current_sinks_map_.end())
current_sinks_map_.erase(old_sink_it);
if (observer_) if (observer_)
observer_->OnSinkAddedOrUpdated(cast_sink, socket); observer_->OnSinkAddedOrUpdated(cast_sink, socket);
...@@ -580,9 +605,14 @@ void CastMediaSinkServiceImpl::OnChannelOpenSucceeded( ...@@ -580,9 +605,14 @@ void CastMediaSinkServiceImpl::OnChannelOpenSucceeded(
} }
void CastMediaSinkServiceImpl::OnChannelOpenFailed( void CastMediaSinkServiceImpl::OnChannelOpenFailed(
const net::IPEndPoint& ip_endpoint) { const net::IPEndPoint& ip_endpoint,
const MediaSinkInternal& sink) {
// It is possible that the old sink in |current_sinks_map_| is replaced with
// a new sink if a network change happened. Check the sink ID to make sure
// this is the sink we want to erase.
auto it = current_sinks_map_.find(ip_endpoint); auto it = current_sinks_map_.find(ip_endpoint);
if (it == current_sinks_map_.end()) if (it == current_sinks_map_.end() ||
it->second.sink().id() != sink.sink().id())
return; return;
if (observer_) if (observer_)
......
...@@ -169,6 +169,10 @@ class CastMediaSinkServiceImpl ...@@ -169,6 +169,10 @@ class CastMediaSinkServiceImpl
TestInitRetryParametersWithDefaultValue); TestInitRetryParametersWithDefaultValue);
FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest, FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
TestOnDialSinkAddedSkipsIfNonCastDevice); TestOnDialSinkAddedSkipsIfNonCastDevice);
FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
TestOnChannelErrorRetry);
FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceImplTest,
OpenChannelNewIPSameSink);
// Holds Finch field trial parameters controlling Cast channel retry strategy. // Holds Finch field trial parameters controlling Cast channel retry strategy.
struct RetryParams { struct RetryParams {
...@@ -276,7 +280,7 @@ class CastMediaSinkServiceImpl ...@@ -276,7 +280,7 @@ class CastMediaSinkServiceImpl
cast_channel::ChannelError error_state, cast_channel::ChannelError error_state,
SinkSource sink_source); SinkSource sink_source);
// Invoked when opening cast channel on IO thread succeeds. // Invoked when opening cast channel succeeds.
// |cast_sink|: Cast sink created from mDNS service description or DIAL sink. // |cast_sink|: Cast sink created from mDNS service description or DIAL sink.
// |socket|: raw pointer of newly created cast channel. Does not take // |socket|: raw pointer of newly created cast channel. Does not take
// ownership of |socket|. // ownership of |socket|.
...@@ -284,11 +288,12 @@ class CastMediaSinkServiceImpl ...@@ -284,11 +288,12 @@ class CastMediaSinkServiceImpl
cast_channel::CastSocket* socket, cast_channel::CastSocket* socket,
SinkSource sink_source); SinkSource sink_source);
// Invoked when opening cast channel on IO thread fails after all retry // Invoked when opening cast channel fails after all retry
// attempts. // attempts.
// |ip_endpoint|: ip endpoint of cast channel failing to connect to. // |ip_endpoint|: ip endpoint of cast channel failing to connect to.
// |sink_source|: Method of sink discovery. // |sink|: The sink for which channel open failed.
void OnChannelOpenFailed(const net::IPEndPoint& ip_endpoint); void OnChannelOpenFailed(const net::IPEndPoint& ip_endpoint,
const MediaSinkInternal& sink);
// Returns whether the given DIAL-discovered |sink| is probably a non-Cast // Returns whether the given DIAL-discovered |sink| is probably a non-Cast
// device. This is heuristically determined by two things: |sink| has been // device. This is heuristically determined by two things: |sink| has been
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment