blob: 4208d73adcf694f4f25cb971ee938dbc98be7269 [file] [log] [blame]
btolsch5b0145a2020-03-24 23:07:171// Copyright 2020 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.
4
5#include "components/cast_channel/keep_alive_handler.h"
6
Peter Boström665b49d2021-04-05 19:29:587#include <memory>
btolsch5b0145a2020-03-24 23:07:178#include <utility>
9
10#include "base/bind.h"
11#include "components/cast_channel/cast_channel_enum.h"
12#include "components/cast_channel/cast_message_util.h"
13#include "components/cast_channel/cast_socket.h"
14#include "components/cast_channel/logger.h"
15#include "net/base/net_errors.h"
16#include "net/traffic_annotation/network_traffic_annotation.h"
17#include "third_party/openscreen/src/cast/common/channel/proto/cast_channel.pb.h"
18
19namespace cast_channel {
20
21KeepAliveHandler::KeepAliveHandler(CastSocket* socket,
22 scoped_refptr<Logger> logger,
23 base::TimeDelta ping_interval,
24 base::TimeDelta liveness_timeout,
25 OnErrorCallback on_error_cb)
26 : started_(false),
27 socket_(socket),
28 logger_(logger),
29 liveness_timeout_(liveness_timeout),
30 ping_interval_(ping_interval),
31 ping_message_(CreateKeepAlivePingMessage()),
32 pong_message_(CreateKeepAlivePongMessage()),
33 on_error_cb_(std::move(on_error_cb)) {
34 DCHECK(ping_interval_ < liveness_timeout_);
35 DCHECK(socket_);
36 DCHECK(!on_error_cb_.is_null());
37}
38
39KeepAliveHandler::~KeepAliveHandler() {
40 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
41}
42
43void KeepAliveHandler::SetTimersForTest(
44 std::unique_ptr<base::RetainingOneShotTimer> injected_ping_timer,
45 std::unique_ptr<base::RetainingOneShotTimer> injected_liveness_timer) {
46 ping_timer_ = std::move(injected_ping_timer);
47 liveness_timer_ = std::move(injected_liveness_timer);
48}
49
50void KeepAliveHandler::Start() {
51 DCHECK(!started_);
52
53 DVLOG(1) << "Starting keep-alive timers.";
54 DVLOG(1) << "Ping interval: " << ping_interval_;
55 DVLOG(1) << "Liveness timeout: " << liveness_timeout_;
56
57 // Use injected mock timers, if provided.
58 if (!ping_timer_) {
Peter Boström665b49d2021-04-05 19:29:5859 ping_timer_ = std::make_unique<base::RetainingOneShotTimer>();
btolsch5b0145a2020-03-24 23:07:1760 }
61 if (!liveness_timer_) {
Peter Boström665b49d2021-04-05 19:29:5862 liveness_timer_ = std::make_unique<base::RetainingOneShotTimer>();
btolsch5b0145a2020-03-24 23:07:1763 }
64
65 ping_timer_->Start(
66 FROM_HERE, ping_interval_,
67 base::BindRepeating(&KeepAliveHandler::SendKeepAliveMessage,
68 base::Unretained(this), ping_message_,
69 CastMessageType::kPing));
70 liveness_timer_->Start(FROM_HERE, liveness_timeout_,
71 base::BindRepeating(&KeepAliveHandler::LivenessTimeout,
72 base::Unretained(this)));
73
74 started_ = true;
75}
76
77bool KeepAliveHandler::HandleMessage(const CastMessage& message) {
78 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
79 DVLOG(2) << "KeepAlive::OnMessage : " << message.payload_utf8();
80
81 if (started_) {
82 ResetTimers();
83 }
84
85 // Keep-alive messages are intercepted and handled by KeepAliveHandler
86 // here. All other messages are passed through to |inner_delegate_|.
87 // Keep-alive messages are assumed to be in the form { "type": "PING|PONG" }.
88 if (message.namespace_() == kHeartbeatNamespace) {
89 static const char* ping_message_type = ToString(CastMessageType::kPing);
90 if (message.payload_utf8().find(ping_message_type) != std::string::npos) {
91 DVLOG(2) << "Received PING.";
92 if (started_)
93 SendKeepAliveMessage(pong_message_, CastMessageType::kPong);
94 } else {
95 DCHECK_NE(std::string::npos,
96 message.payload_utf8().find(ToString(CastMessageType::kPong)));
97 DVLOG(2) << "Received PONG.";
98 }
99 return true;
100 }
101 return false;
102}
103
104void KeepAliveHandler::ResetTimers() {
105 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
106 DCHECK(started_);
107 ping_timer_->Reset();
108 liveness_timer_->Reset();
109}
110
111void KeepAliveHandler::SendKeepAliveMessage(const CastMessage& message,
112 CastMessageType message_type) {
113 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
114 DVLOG(2) << "Sending " << ToString(message_type);
115
116 socket_->transport()->SendMessage(
117 message, base::BindOnce(&KeepAliveHandler::SendKeepAliveMessageComplete,
118 weak_factory_.GetWeakPtr(), message_type));
119}
120
121void KeepAliveHandler::SendKeepAliveMessageComplete(
122 CastMessageType message_type,
123 int rv) {
124 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
125 DVLOG(2) << "Sending " << ToString(message_type) << " complete, rv=" << rv;
126 if (rv != net::OK) {
127 // An error occurred while sending the ping response.
128 DVLOG(1) << "Error sending " << ToString(message_type);
129 logger_->LogSocketEventWithRv(socket_->id(), ChannelEvent::PING_WRITE_ERROR,
130 rv);
131 on_error_cb_.Run(ChannelError::CAST_SOCKET_ERROR);
132 return;
133 }
134
135 if (liveness_timer_)
136 liveness_timer_->Reset();
137}
138
139void KeepAliveHandler::LivenessTimeout() {
140 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
141 on_error_cb_.Run(ChannelError::PING_TIMEOUT);
142 Stop();
143}
144
145void KeepAliveHandler::Stop() {
146 if (started_) {
147 started_ = false;
148 ping_timer_->Stop();
149 liveness_timer_->Stop();
150 }
151}
152
153} // namespace cast_channel