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 virtual ~Delegate() = default; 66 67 // State changes. 68 virtual void OnConnected() = 0; 69 70 // Explicit close by other endpoint. 71 virtual void OnClosedByRemote() = 0; 72 73 // Closed because the script connection object was discarded. 74 virtual void OnDiscarded() = 0; 75 76 // Closed because of an error. 77 virtual void OnError(const absl::string_view message) = 0; 78 79 // Terminated through a different connection. 80 virtual void OnTerminated() = 0; 81 82 // A UTF-8 string message was received. 83 virtual void OnStringMessage(const absl::string_view message) = 0; 84 85 // A binary message was received. 86 virtual void OnBinaryMessage(const std::vector<uint8_t>& data) = 0; 87 88 private: 89 OSP_DISALLOW_COPY_AND_ASSIGN(Delegate); 90 }; 91 92 // Allows different close, termination, and destruction behavior for both 93 // possible parents: controller and receiver. This is different from the 94 // normal delegate above, which would be supplied by the embedder to link it's 95 // presentation connection functionality. 96 class ParentDelegate { 97 public: 98 ParentDelegate() = default; 99 virtual ~ParentDelegate() = default; 100 101 virtual Error CloseConnection(Connection* connection, 102 CloseReason reason) = 0; 103 virtual Error OnPresentationTerminated(const std::string& presentation_id, 104 TerminationReason reason) = 0; 105 virtual void OnConnectionDestroyed(Connection* connection) = 0; 106 107 private: 108 OSP_DISALLOW_COPY_AND_ASSIGN(ParentDelegate); 109 }; 110 111 struct PresentationInfo { 112 std::string id; 113 std::string url; 114 }; 115 116 // Constructs a new connection using |delegate| for callbacks. 117 Connection(const PresentationInfo& info, 118 Delegate* delegate, 119 ParentDelegate* parent_delegate); 120 ~Connection(); 121 122 // Returns the ID and URL of this presentation. presentation_info()123 const PresentationInfo& presentation_info() const { return presentation_; } 124 state()125 State state() const { return state_; } 126 get_protocol_connection()127 ProtocolConnection* get_protocol_connection() const { 128 return protocol_connection_.get(); 129 } 130 131 // These methods should only be called when we are connected. endpoint_id()132 uint64_t endpoint_id() const { 133 OSP_CHECK(endpoint_id_); 134 return endpoint_id_.value(); 135 } connection_id()136 uint64_t connection_id() const { 137 OSP_CHECK(connection_id_); 138 return connection_id_.value(); 139 } 140 141 // Sends a UTF-8 string message. 142 Error SendString(absl::string_view message); 143 144 // Sends a binary message. 145 Error SendBinary(std::vector<uint8_t>&& data); 146 147 // Closes the connection. This can be based on an explicit request from the 148 // embedder or because the connection object is being discarded (page 149 // navigated, object GC'd, etc.). 150 Error Close(CloseReason reason); 151 152 // Terminates the presentation associated with this connection. 153 void Terminate(TerminationReason reason); 154 155 void OnConnecting(); 156 157 // Called by the receiver when the OnPresentationStarted logic happens. This 158 // notifies the delegate and updates our internal stream and ids. 159 void OnConnected(uint64_t connection_id, 160 uint64_t endpoint_id, 161 std::unique_ptr<ProtocolConnection> stream); 162 163 void OnClosedByError(Error cause); 164 void OnClosedByRemote(); 165 void OnTerminated(); 166 get_delegate()167 Delegate* get_delegate() { return delegate_; } 168 169 private: 170 // Helper method that handles closing down our internal state. 171 // Returns whether or not the connection state changed (and thus 172 // whether or not delegates should be informed). 173 bool OnClosed(); 174 175 PresentationInfo presentation_; 176 State state_ = State::kConnecting; 177 Delegate* delegate_; 178 ParentDelegate* parent_delegate_; 179 absl::optional<uint64_t> connection_id_; 180 absl::optional<uint64_t> endpoint_id_; 181 std::unique_ptr<ProtocolConnection> protocol_connection_; 182 183 OSP_DISALLOW_COPY_AND_ASSIGN(Connection); 184 }; 185 186 class ConnectionManager final : public MessageDemuxer::MessageCallback { 187 public: 188 explicit ConnectionManager(MessageDemuxer* demuxer); 189 190 void AddConnection(Connection* connection); 191 void RemoveConnection(Connection* connection); 192 193 // MessasgeDemuxer::MessageCallback overrides. 194 ErrorOr<size_t> OnStreamMessage(uint64_t endpoint_id, 195 uint64_t connection_id, 196 msgs::Type message_type, 197 const uint8_t* buffer, 198 size_t buffer_size, 199 Clock::time_point now) override; 200 201 Connection* GetConnection(uint64_t connection_id); 202 203 private: 204 // TODO(btolsch): Connection IDs were changed to be per-endpoint, but this 205 // table then needs to be <endpoint id, connection id> since connection id is 206 // still not unique globally. 207 std::map<uint64_t, Connection*> connections_; 208 209 MessageDemuxer::MessageWatch message_watch_; 210 MessageDemuxer::MessageWatch close_request_watch_; 211 MessageDemuxer::MessageWatch close_event_watch_; 212 213 OSP_DISALLOW_COPY_AND_ASSIGN(ConnectionManager); 214 }; 215 216 } // namespace osp 217 } // namespace openscreen 218 219 #endif // OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_ 220