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 OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ 6 #define OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ 7 8 #include <cstdint> 9 #include <map> 10 #include <memory> 11 #include <string> 12 #include <vector> 13 14 #include "absl/strings/string_view.h" 15 #include "absl/types/optional.h" 16 #include "osp/public/message_demuxer.h" 17 #include "platform/api/time.h" 18 #include "platform/base/error.h" 19 #include "platform/base/ip_address.h" 20 #include "platform/base/macros.h" 21 #include "util/osp_logging.h" 22 23 namespace openscreen { 24 namespace osp { 25 26 class ProtocolConnection; 27 28 enum class TerminationReason { 29 kReceiverTerminateCalled = 0, 30 kReceiverUserTerminated, 31 kControllerTerminateCalled, 32 kControllerUserTerminated, 33 kReceiverPresentationReplaced, 34 kReceiverIdleTooLong, 35 kReceiverPresentationUnloaded, 36 kReceiverShuttingDown, 37 kReceiverError, 38 }; 39 40 class Connection { 41 public: 42 enum class CloseReason { 43 kClosed = 0, 44 kDiscarded, 45 kError, 46 }; 47 48 enum class State { 49 // The library is currently attempting to connect to the presentation. 50 kConnecting, 51 // The connection to the presentation is open and communication is possible. 52 kConnected, 53 // The connection is closed or could not be opened. No communication is 54 // possible but it may be possible to reopen the connection via 55 // ReconnectPresentation. 56 kClosed, 57 // The connection is closed and the receiver has been terminated. 58 kTerminated, 59 }; 60 61 // An object to receive callbacks related to a single Connection. 62 class Delegate { 63 public: 64 Delegate() = default; 65 66 // State changes. 67 virtual void OnConnected() = 0; 68 69 // Explicit close by other endpoint. 70 virtual void OnClosedByRemote() = 0; 71 72 // Closed because the script connection object was discarded. 73 virtual void OnDiscarded() = 0; 74 75 // Closed because of an error. 76 virtual void OnError(const absl::string_view message) = 0; 77 78 // Terminated through a different connection. 79 virtual void OnTerminated() = 0; 80 81 // A UTF-8 string message was received. 82 virtual void OnStringMessage(const absl::string_view message) = 0; 83 84 // A binary message was received. 85 virtual void OnBinaryMessage(const std::vector<uint8_t>& data) = 0; 86 87 protected: 88 virtual ~Delegate() = default; 89 90 private: 91 OSP_DISALLOW_COPY_AND_ASSIGN(Delegate); 92 }; 93 94 // Allows different close, termination, and destruction behavior for both 95 // possible parents: controller and receiver. This is different from the 96 // normal delegate above, which would be supplied by the embedder to link it's 97 // presentation connection functionality. 98 class ParentDelegate { 99 public: 100 ParentDelegate() = default; 101 virtual ~ParentDelegate() = default; 102 103 virtual Error CloseConnection(Connection* connection, 104 CloseReason reason) = 0; 105 virtual Error OnPresentationTerminated(const std::string& presentation_id, 106 TerminationReason reason) = 0; 107 virtual void OnConnectionDestroyed(Connection* connection) = 0; 108 109 private: 110 OSP_DISALLOW_COPY_AND_ASSIGN(ParentDelegate); 111 }; 112 113 struct PresentationInfo { 114 std::string id; 115 std::string url; 116 }; 117 118 // Constructs a new connection using |delegate| for callbacks. 119 Connection(const PresentationInfo& info, 120 Delegate* delegate, 121 ParentDelegate* parent_delegate); 122 ~Connection(); 123 124 // Returns the ID and URL of this presentation. presentation_info()125 const PresentationInfo& presentation_info() const { return presentation_; } 126 state()127 State state() const { return state_; } 128 get_protocol_connection()129 ProtocolConnection* get_protocol_connection() const { 130 return protocol_connection_.get(); 131 } 132 133 // These methods should only be called when we are connected. endpoint_id()134 uint64_t endpoint_id() const { 135 OSP_CHECK(endpoint_id_); 136 return endpoint_id_.value(); 137 } connection_id()138 uint64_t connection_id() const { 139 OSP_CHECK(connection_id_); 140 return connection_id_.value(); 141 } 142 143 // Sends a UTF-8 string message. 144 Error SendString(absl::string_view message); 145 146 // Sends a binary message. 147 Error SendBinary(std::vector<uint8_t>&& data); 148 149 // Closes the connection. This can be based on an explicit request from the 150 // embedder or because the connection object is being discarded (page 151 // navigated, object GC'd, etc.). 152 Error Close(CloseReason reason); 153 154 // Terminates the presentation associated with this connection. 155 void Terminate(TerminationReason reason); 156 157 void OnConnecting(); 158 159 // Called by the receiver when the OnPresentationStarted logic happens. This 160 // notifies the delegate and updates our internal stream and ids. 161 void OnConnected(uint64_t connection_id, 162 uint64_t endpoint_id, 163 std::unique_ptr<ProtocolConnection> stream); 164 165 void OnClosedByError(Error cause); 166 void OnClosedByRemote(); 167 void OnTerminated(); 168 get_delegate()169 Delegate* get_delegate() { return delegate_; } 170 171 private: 172 // Helper method that handles closing down our internal state. 173 // Returns whether or not the connection state changed (and thus 174 // whether or not delegates should be informed). 175 bool OnClosed(); 176 177 PresentationInfo presentation_; 178 State state_ = State::kConnecting; 179 Delegate* delegate_; 180 ParentDelegate* parent_delegate_; 181 absl::optional<uint64_t> connection_id_; 182 absl::optional<uint64_t> endpoint_id_; 183 std::unique_ptr<ProtocolConnection> protocol_connection_; 184 185 OSP_DISALLOW_COPY_AND_ASSIGN(Connection); 186 }; 187 188 class ConnectionManager final : public MessageDemuxer::MessageCallback { 189 public: 190 explicit ConnectionManager(MessageDemuxer* demuxer); 191 192 void AddConnection(Connection* connection); 193 void RemoveConnection(Connection* connection); 194 195 // MessasgeDemuxer::MessageCallback overrides. 196 ErrorOr<size_t> OnStreamMessage(uint64_t endpoint_id, 197 uint64_t connection_id, 198 msgs::Type message_type, 199 const uint8_t* buffer, 200 size_t buffer_size, 201 Clock::time_point now) override; 202 203 Connection* GetConnection(uint64_t connection_id); 204 205 private: 206 // TODO(btolsch): Connection IDs were changed to be per-endpoint, but this 207 // table then needs to be <endpoint id, connection id> since connection id is 208 // still not unique globally. 209 std::map<uint64_t, Connection*> connections_; 210 211 MessageDemuxer::MessageWatch message_watch_; 212 MessageDemuxer::MessageWatch close_request_watch_; 213 MessageDemuxer::MessageWatch close_event_watch_; 214 215 OSP_DISALLOW_COPY_AND_ASSIGN(ConnectionManager); 216 }; 217 218 } // namespace osp 219 } // namespace openscreen 220 221 #endif // OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ 222