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