1 // Copyright 2019 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 #ifndef REMOTING_HOST_HEARTBEAT_SENDER_H_ 6 #define REMOTING_HOST_HEARTBEAT_SENDER_H_ 7 8 #include <memory> 9 #include <string> 10 11 #include "base/callback.h" 12 #include "base/gtest_prod_util.h" 13 #include "base/macros.h" 14 #include "base/sequence_checker.h" 15 #include "base/timer/timer.h" 16 #include "net/base/backoff_entry.h" 17 #include "remoting/proto/remoting/v1/directory_messages.pb.h" 18 #include "remoting/signaling/signal_strategy.h" 19 20 namespace base { 21 class TimeDelta; 22 } // namespace base 23 24 namespace network { 25 class SharedURLLoaderFactory; 26 } // namespace network 27 28 namespace remoting { 29 30 class OAuthTokenGetter; 31 class ProtobufHttpStatus; 32 33 // HeartbeatSender periodically sends heartbeat to the directory service. See 34 // the HeartbeatRequest message in directory_messages.proto for more details. 35 // 36 // Normally the heartbeat indicates that the host is healthy and ready to 37 // accept new connections from a client, but the message can optionally include 38 // a host_offline_reason field, which indicates that the host cannot accept 39 // connections from the client (and might possibly be shutting down). The value 40 // of the host_offline_reason field can be either a string from 41 // host_exit_codes.cc (i.e. "INVALID_HOST_CONFIGURATION" string) or one of 42 // kHostOfflineReasonXxx constants (i.e. "POLICY_READ_ERROR" string). 43 // 44 // The heartbeat sender will verify that the channel is in fact active before 45 // sending out the heartbeat. If not, it will disconnect the signaling strategy 46 // so that the signaling connector will try to reconnect signaling. 47 // 48 // The server sends a HeartbeatResponse in response to each successful 49 // heartbeat, which may contain a remote command to be executed on the host, 50 // e.g. restarting the host process upon reception of the response. 51 class HeartbeatSender final : public SignalStrategy::Listener { 52 public: 53 class Delegate { 54 public: 55 virtual ~Delegate() = default; 56 57 // Invoked after the first successful heartbeat. 58 virtual void OnFirstHeartbeatSuccessful() = 0; 59 60 // Invoked when the host is not found in the directory. 61 virtual void OnHostNotFound() = 0; 62 63 // Invoked when the heartbeat sender permanently fails to authenticate the 64 // requests. 65 virtual void OnAuthFailed() = 0; 66 67 // Invoked when the host has been asked to restart. 68 virtual void OnRemoteRestartHost() = 0; 69 70 protected: 71 Delegate() = default; 72 }; 73 74 // Interface to track heartbeat events for diagnosis purpose. 75 class Observer { 76 public: 77 virtual ~Observer() = default; 78 79 // Invoked when the heartbeat sender has sent a heartbeat. 80 virtual void OnHeartbeatSent() = 0; 81 82 protected: 83 Observer() = default; 84 }; 85 86 // All raw pointers must be non-null and outlive this object. 87 HeartbeatSender( 88 Delegate* delegate, 89 const std::string& host_id, 90 SignalStrategy* signal_strategy, 91 OAuthTokenGetter* oauth_token_getter, 92 Observer* observer, 93 scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, 94 bool is_googler); 95 ~HeartbeatSender() override; 96 97 // Sets host offline reason for future heartbeat, and initiates sending a 98 // heartbeat right away. 99 // 100 // For discussion of allowed values for |host_offline_reason| argument, 101 // please see the description in the class-level comments above. 102 // 103 // |ack_callback| will be called when the server acks receiving the 104 // |host_offline_reason| or when |timeout| is reached. 105 void SetHostOfflineReason( 106 const std::string& host_offline_reason, 107 const base::TimeDelta& timeout, 108 base::OnceCallback<void(bool success)> ack_callback); 109 110 private: 111 class HeartbeatClient { 112 public: 113 using HeartbeatResponseCallback = 114 base::OnceCallback<void(const ProtobufHttpStatus&, 115 std::unique_ptr<apis::v1::HeartbeatResponse>)>; 116 117 virtual ~HeartbeatClient() = default; 118 119 virtual void Heartbeat(std::unique_ptr<apis::v1::HeartbeatRequest> request, 120 HeartbeatResponseCallback callback) = 0; 121 virtual void CancelPendingRequests() = 0; 122 }; 123 124 class HeartbeatClientImpl; 125 126 friend class HeartbeatSenderTest; 127 128 // SignalStrategy::Listener interface. 129 void OnSignalStrategyStateChange(SignalStrategy::State state) override; 130 bool OnSignalStrategyIncomingStanza( 131 const jingle_xmpp::XmlElement* stanza) override; 132 133 void SendHeartbeat(); 134 void OnResponse(const ProtobufHttpStatus& status, 135 std::unique_ptr<apis::v1::HeartbeatResponse> response); 136 137 // Handlers for host-offline-reason completion and timeout. 138 void OnHostOfflineReasonTimeout(); 139 void OnHostOfflineReasonAck(); 140 141 void OnRemoteCommand( 142 apis::v1::HeartbeatResponse::RemoteCommand remote_command); 143 144 // Helper methods used by DoSendStanza() to generate heartbeat stanzas. 145 std::unique_ptr<apis::v1::HeartbeatRequest> CreateHeartbeatRequest(); 146 147 Delegate* delegate_; 148 std::string host_id_; 149 SignalStrategy* const signal_strategy_; 150 std::unique_ptr<HeartbeatClient> client_; 151 OAuthTokenGetter* const oauth_token_getter_; 152 Observer* observer_; 153 154 base::OneShotTimer heartbeat_timer_; 155 156 net::BackoffEntry backoff_; 157 158 bool initial_heartbeat_sent_ = false; 159 160 bool is_googler_ = false; 161 162 // Fields to send and indicate completion of sending host-offline-reason. 163 std::string host_offline_reason_; 164 base::OnceCallback<void(bool success)> host_offline_reason_ack_callback_; 165 base::OneShotTimer host_offline_reason_timeout_timer_; 166 167 SEQUENCE_CHECKER(sequence_checker_); 168 169 DISALLOW_COPY_AND_ASSIGN(HeartbeatSender); 170 }; 171 172 } // namespace remoting 173 174 #endif // REMOTING_HOST_HEARTBEAT_SENDER_H_ 175