| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef REMOTING_HOST_HEARTBEAT_SENDER_H_ |
| #define REMOTING_HOST_HEARTBEAT_SENDER_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/callback.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/macros.h" |
| #include "base/sequence_checker.h" |
| #include "base/timer/timer.h" |
| #include "net/base/backoff_entry.h" |
| #include "remoting/proto/remoting/v1/directory_messages.pb.h" |
| #include "remoting/signaling/signal_strategy.h" |
| |
| namespace base { |
| class TimeDelta; |
| } // namespace base |
| |
| namespace network { |
| class SharedURLLoaderFactory; |
| } // namespace network |
| |
| namespace remoting { |
| |
| class OAuthTokenGetter; |
| class ProtobufHttpStatus; |
| |
| // HeartbeatSender periodically sends heartbeat to the directory service. See |
| // the HeartbeatRequest message in directory_messages.proto for more details. |
| // |
| // Normally the heartbeat indicates that the host is healthy and ready to |
| // accept new connections from a client, but the message can optionally include |
| // a host_offline_reason field, which indicates that the host cannot accept |
| // connections from the client (and might possibly be shutting down). The value |
| // of the host_offline_reason field can be either a string from |
| // host_exit_codes.cc (i.e. "INVALID_HOST_CONFIGURATION" string) or one of |
| // kHostOfflineReasonXxx constants (i.e. "POLICY_READ_ERROR" string). |
| // |
| // The heartbeat sender will verify that the channel is in fact active before |
| // sending out the heartbeat. If not, it will disconnect the signaling strategy |
| // so that the signaling connector will try to reconnect signaling. |
| // |
| // The server sends a HeartbeatResponse in response to each successful |
| // heartbeat. |
| class HeartbeatSender final : public SignalStrategy::Listener { |
| public: |
| class Delegate { |
| public: |
| virtual ~Delegate() = default; |
| |
| // Invoked after the first successful heartbeat. |
| virtual void OnFirstHeartbeatSuccessful() = 0; |
| |
| // Invoked when the host is not found in the directory. |
| virtual void OnHostNotFound() = 0; |
| |
| // Invoked when the heartbeat sender permanently fails to authenticate the |
| // requests. |
| virtual void OnAuthFailed() = 0; |
| |
| protected: |
| Delegate() = default; |
| }; |
| |
| // Interface to track heartbeat events for diagnosis purpose. |
| class Observer { |
| public: |
| virtual ~Observer() = default; |
| |
| // Invoked when the heartbeat sender has sent a heartbeat. |
| virtual void OnHeartbeatSent() = 0; |
| |
| protected: |
| Observer() = default; |
| }; |
| |
| // All raw pointers must be non-null and outlive this object. |
| HeartbeatSender( |
| Delegate* delegate, |
| const std::string& host_id, |
| SignalStrategy* signal_strategy, |
| OAuthTokenGetter* oauth_token_getter, |
| Observer* observer, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| bool is_googler); |
| ~HeartbeatSender() override; |
| |
| // Sets host offline reason for future heartbeat, and initiates sending a |
| // heartbeat right away. |
| // |
| // For discussion of allowed values for |host_offline_reason| argument, |
| // please see the description in the class-level comments above. |
| // |
| // |ack_callback| will be called when the server acks receiving the |
| // |host_offline_reason| or when |timeout| is reached. |
| void SetHostOfflineReason( |
| const std::string& host_offline_reason, |
| const base::TimeDelta& timeout, |
| base::OnceCallback<void(bool success)> ack_callback); |
| |
| private: |
| class HeartbeatClient { |
| public: |
| using HeartbeatResponseCallback = |
| base::OnceCallback<void(const ProtobufHttpStatus&, |
| std::unique_ptr<apis::v1::HeartbeatResponse>)>; |
| |
| virtual ~HeartbeatClient() = default; |
| |
| virtual void Heartbeat(std::unique_ptr<apis::v1::HeartbeatRequest> request, |
| HeartbeatResponseCallback callback) = 0; |
| virtual void CancelPendingRequests() = 0; |
| }; |
| |
| class HeartbeatClientImpl; |
| |
| friend class HeartbeatSenderTest; |
| |
| // SignalStrategy::Listener interface. |
| void OnSignalStrategyStateChange(SignalStrategy::State state) override; |
| bool OnSignalStrategyIncomingStanza( |
| const jingle_xmpp::XmlElement* stanza) override; |
| |
| void SendHeartbeat(); |
| void OnResponse(const ProtobufHttpStatus& status, |
| std::unique_ptr<apis::v1::HeartbeatResponse> response); |
| |
| // Handlers for host-offline-reason completion and timeout. |
| void OnHostOfflineReasonTimeout(); |
| void OnHostOfflineReasonAck(); |
| |
| // Helper methods used by DoSendStanza() to generate heartbeat stanzas. |
| std::unique_ptr<apis::v1::HeartbeatRequest> CreateHeartbeatRequest(); |
| |
| Delegate* delegate_; |
| std::string host_id_; |
| SignalStrategy* const signal_strategy_; |
| std::unique_ptr<HeartbeatClient> client_; |
| OAuthTokenGetter* const oauth_token_getter_; |
| Observer* observer_; |
| |
| base::OneShotTimer heartbeat_timer_; |
| |
| net::BackoffEntry backoff_; |
| |
| bool initial_heartbeat_sent_ = false; |
| |
| bool is_googler_ = false; |
| |
| // Fields to send and indicate completion of sending host-offline-reason. |
| std::string host_offline_reason_; |
| base::OnceCallback<void(bool success)> host_offline_reason_ack_callback_; |
| base::OneShotTimer host_offline_reason_timeout_timer_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| DISALLOW_COPY_AND_ASSIGN(HeartbeatSender); |
| }; |
| |
| } // namespace remoting |
| |
| #endif // REMOTING_HOST_HEARTBEAT_SENDER_H_ |