1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/cast_channel/keep_alive_delegate.h"
10 #include "components/cast_channel/cast_channel_enum.h"
11 #include "components/cast_channel/cast_socket.h"
12 #include "components/cast_channel/logger.h"
13 #include "components/cast_channel/proto/cast_channel.pb.h"
14 #include "net/base/net_errors.h"
15 #include "net/traffic_annotation/network_traffic_annotation.h"
17 namespace cast_channel {
19 using ::cast_channel::ChannelError;
21 KeepAliveDelegate::KeepAliveDelegate(
23 scoped_refptr<Logger> logger,
24 std::unique_ptr<CastTransport::Delegate> inner_delegate,
25 base::TimeDelta ping_interval,
26 base::TimeDelta liveness_timeout)
30 inner_delegate_(std::move(inner_delegate)),
31 liveness_timeout_(liveness_timeout),
32 ping_interval_(ping_interval),
33 ping_message_(CreateKeepAlivePingMessage()),
34 pong_message_(CreateKeepAlivePongMessage()),
36 DCHECK(ping_interval_ < liveness_timeout_);
37 DCHECK(inner_delegate_);
41 KeepAliveDelegate::~KeepAliveDelegate() {
42 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
45 void KeepAliveDelegate::SetTimersForTest(
46 std::unique_ptr<base::RetainingOneShotTimer> injected_ping_timer,
47 std::unique_ptr<base::RetainingOneShotTimer> injected_liveness_timer) {
48 ping_timer_ = std::move(injected_ping_timer);
49 liveness_timer_ = std::move(injected_liveness_timer);
52 void KeepAliveDelegate::Start() {
53 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
56 DVLOG(1) << "Starting keep-alive timers.";
57 DVLOG(1) << "Ping timeout: " << ping_interval_;
58 DVLOG(1) << "Liveness timeout: " << liveness_timeout_;
60 // Use injected mock timers, if provided.
62 ping_timer_.reset(new base::RetainingOneShotTimer());
64 if (!liveness_timer_) {
65 liveness_timer_.reset(new base::RetainingOneShotTimer());
69 FROM_HERE, ping_interval_,
70 base::BindRepeating(&KeepAliveDelegate::SendKeepAliveMessage,
71 base::Unretained(this), ping_message_,
72 CastMessageType::kPing));
73 liveness_timer_->Start(
74 FROM_HERE, liveness_timeout_,
75 base::BindRepeating(&KeepAliveDelegate::LivenessTimeout,
76 base::Unretained(this)));
79 inner_delegate_->Start();
82 void KeepAliveDelegate::ResetTimers() {
83 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
86 liveness_timer_->Reset();
89 void KeepAliveDelegate::SendKeepAliveMessage(const CastMessage& message,
90 CastMessageType message_type) {
91 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
92 DVLOG(2) << "Sending " << ToString(message_type);
94 socket_->transport()->SendMessage(
95 message, base::Bind(&KeepAliveDelegate::SendKeepAliveMessageComplete,
96 weak_factory_.GetWeakPtr(), message_type));
99 void KeepAliveDelegate::SendKeepAliveMessageComplete(
100 CastMessageType message_type,
102 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
103 DVLOG(2) << "Sending " << ToString(message_type) << " complete, rv=" << rv;
105 // An error occurred while sending the ping response.
106 DVLOG(1) << "Error sending " << ToString(message_type);
107 logger_->LogSocketEventWithRv(socket_->id(), ChannelEvent::PING_WRITE_ERROR,
109 OnError(ChannelError::CAST_SOCKET_ERROR);
114 liveness_timer_->Reset();
117 void KeepAliveDelegate::LivenessTimeout() {
118 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
119 OnError(ChannelError::PING_TIMEOUT);
123 // CastTransport::Delegate interface.
124 void KeepAliveDelegate::OnError(ChannelError error_state) {
125 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
126 DVLOG(1) << "KeepAlive::OnError: "
127 << ::cast_channel::ChannelErrorToString(error_state);
128 inner_delegate_->OnError(error_state);
132 void KeepAliveDelegate::OnMessage(const CastMessage& message) {
133 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
134 DVLOG(2) << "KeepAlive::OnMessage : " << message.payload_utf8();
139 // Keep-alive messages are intercepted and handled by KeepAliveDelegate
140 // here. All other messages are passed through to |inner_delegate_|.
141 // Keep-alive messages are assumed to be in the form { "type": "PING|PONG" }.
142 if (message.namespace_() == kHeartbeatNamespace) {
143 const char* ping_message_type = ToString(CastMessageType::kPing);
144 if (message.payload_utf8().find(ping_message_type) != std::string::npos) {
145 DVLOG(2) << "Received PING.";
147 SendKeepAliveMessage(pong_message_, CastMessageType::kPong);
149 DCHECK_NE(std::string::npos,
150 message.payload_utf8().find(ToString(CastMessageType::kPong)));
151 DVLOG(2) << "Received PONG.";
154 inner_delegate_->OnMessage(message);
158 void KeepAliveDelegate::Stop() {
162 liveness_timer_->Stop();
166 } // namespace cast_channel