// 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 OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ #define OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ #include #include #include #include #include #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "osp/public/message_demuxer.h" #include "platform/api/time.h" #include "platform/base/error.h" #include "platform/base/ip_address.h" #include "platform/base/macros.h" #include "util/osp_logging.h" namespace openscreen { namespace osp { class ProtocolConnection; enum class TerminationReason { kReceiverTerminateCalled = 0, kReceiverUserTerminated, kControllerTerminateCalled, kControllerUserTerminated, kReceiverPresentationReplaced, kReceiverIdleTooLong, kReceiverPresentationUnloaded, kReceiverShuttingDown, kReceiverError, }; class Connection { public: enum class CloseReason { kClosed = 0, kDiscarded, kError, }; enum class State { // The library is currently attempting to connect to the presentation. kConnecting, // The connection to the presentation is open and communication is possible. kConnected, // The connection is closed or could not be opened. No communication is // possible but it may be possible to reopen the connection via // ReconnectPresentation. kClosed, // The connection is closed and the receiver has been terminated. kTerminated, }; // An object to receive callbacks related to a single Connection. class Delegate { public: Delegate() = default; virtual ~Delegate() = default; // State changes. virtual void OnConnected() = 0; // Explicit close by other endpoint. virtual void OnClosedByRemote() = 0; // Closed because the script connection object was discarded. virtual void OnDiscarded() = 0; // Closed because of an error. virtual void OnError(const absl::string_view message) = 0; // Terminated through a different connection. virtual void OnTerminated() = 0; // A UTF-8 string message was received. virtual void OnStringMessage(const absl::string_view message) = 0; // A binary message was received. virtual void OnBinaryMessage(const std::vector& data) = 0; private: OSP_DISALLOW_COPY_AND_ASSIGN(Delegate); }; // Allows different close, termination, and destruction behavior for both // possible parents: controller and receiver. This is different from the // normal delegate above, which would be supplied by the embedder to link it's // presentation connection functionality. class ParentDelegate { public: ParentDelegate() = default; virtual ~ParentDelegate() = default; virtual Error CloseConnection(Connection* connection, CloseReason reason) = 0; virtual Error OnPresentationTerminated(const std::string& presentation_id, TerminationReason reason) = 0; virtual void OnConnectionDestroyed(Connection* connection) = 0; private: OSP_DISALLOW_COPY_AND_ASSIGN(ParentDelegate); }; struct PresentationInfo { std::string id; std::string url; }; // Constructs a new connection using |delegate| for callbacks. Connection(const PresentationInfo& info, Delegate* delegate, ParentDelegate* parent_delegate); ~Connection(); // Returns the ID and URL of this presentation. const PresentationInfo& presentation_info() const { return presentation_; } State state() const { return state_; } ProtocolConnection* get_protocol_connection() const { return protocol_connection_.get(); } // These methods should only be called when we are connected. uint64_t endpoint_id() const { OSP_CHECK(endpoint_id_); return endpoint_id_.value(); } uint64_t connection_id() const { OSP_CHECK(connection_id_); return connection_id_.value(); } // Sends a UTF-8 string message. Error SendString(absl::string_view message); // Sends a binary message. Error SendBinary(std::vector&& data); // Closes the connection. This can be based on an explicit request from the // embedder or because the connection object is being discarded (page // navigated, object GC'd, etc.). Error Close(CloseReason reason); // Terminates the presentation associated with this connection. void Terminate(TerminationReason reason); void OnConnecting(); // Called by the receiver when the OnPresentationStarted logic happens. This // notifies the delegate and updates our internal stream and ids. void OnConnected(uint64_t connection_id, uint64_t endpoint_id, std::unique_ptr stream); void OnClosedByError(Error cause); void OnClosedByRemote(); void OnTerminated(); Delegate* get_delegate() { return delegate_; } private: // Helper method that handles closing down our internal state. // Returns whether or not the connection state changed (and thus // whether or not delegates should be informed). bool OnClosed(); PresentationInfo presentation_; State state_ = State::kConnecting; Delegate* delegate_; ParentDelegate* parent_delegate_; absl::optional connection_id_; absl::optional endpoint_id_; std::unique_ptr protocol_connection_; OSP_DISALLOW_COPY_AND_ASSIGN(Connection); }; class ConnectionManager final : public MessageDemuxer::MessageCallback { public: explicit ConnectionManager(MessageDemuxer* demuxer); void AddConnection(Connection* connection); void RemoveConnection(Connection* connection); // MessasgeDemuxer::MessageCallback overrides. ErrorOr OnStreamMessage(uint64_t endpoint_id, uint64_t connection_id, msgs::Type message_type, const uint8_t* buffer, size_t buffer_size, Clock::time_point now) override; Connection* GetConnection(uint64_t connection_id); private: // TODO(btolsch): Connection IDs were changed to be per-endpoint, but this // table then needs to be since connection id is // still not unique globally. std::map connections_; MessageDemuxer::MessageWatch message_watch_; MessageDemuxer::MessageWatch close_request_watch_; MessageDemuxer::MessageWatch close_event_watch_; OSP_DISALLOW_COPY_AND_ASSIGN(ConnectionManager); }; } // namespace osp } // namespace openscreen #endif // OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_