1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "osp/public/presentation/presentation_connection.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <memory>
9*3f982cf4SFabien Sanglard #include <ostream>
10*3f982cf4SFabien Sanglard
11*3f982cf4SFabien Sanglard #include "absl/strings/string_view.h"
12*3f982cf4SFabien Sanglard #include "osp/impl/presentation/presentation_common.h"
13*3f982cf4SFabien Sanglard #include "osp/msgs/osp_messages.h"
14*3f982cf4SFabien Sanglard #include "osp/public/network_service_manager.h"
15*3f982cf4SFabien Sanglard #include "osp/public/presentation/presentation_controller.h"
16*3f982cf4SFabien Sanglard #include "osp/public/presentation/presentation_receiver.h"
17*3f982cf4SFabien Sanglard #include "osp/public/protocol_connection.h"
18*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
19*3f982cf4SFabien Sanglard #include "util/std_util.h"
20*3f982cf4SFabien Sanglard
21*3f982cf4SFabien Sanglard // TODO(crbug.com/openscreen/27): Address TODOs in this file
22*3f982cf4SFabien Sanglard
23*3f982cf4SFabien Sanglard namespace openscreen {
24*3f982cf4SFabien Sanglard namespace osp {
25*3f982cf4SFabien Sanglard
26*3f982cf4SFabien Sanglard namespace {
27*3f982cf4SFabien Sanglard
28*3f982cf4SFabien Sanglard // TODO(jophba): replace Write methods with a unified write message surface
WriteConnectionMessage(const msgs::PresentationConnectionMessage & message,ProtocolConnection * connection)29*3f982cf4SFabien Sanglard Error WriteConnectionMessage(const msgs::PresentationConnectionMessage& message,
30*3f982cf4SFabien Sanglard ProtocolConnection* connection) {
31*3f982cf4SFabien Sanglard return connection->WriteMessage(message,
32*3f982cf4SFabien Sanglard msgs::EncodePresentationConnectionMessage);
33*3f982cf4SFabien Sanglard }
34*3f982cf4SFabien Sanglard } // namespace
35*3f982cf4SFabien Sanglard
Connection(const PresentationInfo & info,Delegate * delegate,ParentDelegate * parent_delegate)36*3f982cf4SFabien Sanglard Connection::Connection(const PresentationInfo& info,
37*3f982cf4SFabien Sanglard Delegate* delegate,
38*3f982cf4SFabien Sanglard ParentDelegate* parent_delegate)
39*3f982cf4SFabien Sanglard : presentation_(info),
40*3f982cf4SFabien Sanglard state_(State::kConnecting),
41*3f982cf4SFabien Sanglard delegate_(delegate),
42*3f982cf4SFabien Sanglard parent_delegate_(parent_delegate),
43*3f982cf4SFabien Sanglard connection_id_(0),
44*3f982cf4SFabien Sanglard protocol_connection_(nullptr) {}
45*3f982cf4SFabien Sanglard
~Connection()46*3f982cf4SFabien Sanglard Connection::~Connection() {
47*3f982cf4SFabien Sanglard if (state_ == State::kConnected) {
48*3f982cf4SFabien Sanglard Close(CloseReason::kDiscarded);
49*3f982cf4SFabien Sanglard delegate_->OnDiscarded();
50*3f982cf4SFabien Sanglard }
51*3f982cf4SFabien Sanglard parent_delegate_->OnConnectionDestroyed(this);
52*3f982cf4SFabien Sanglard }
53*3f982cf4SFabien Sanglard
OnConnecting()54*3f982cf4SFabien Sanglard void Connection::OnConnecting() {
55*3f982cf4SFabien Sanglard OSP_DCHECK(!protocol_connection_);
56*3f982cf4SFabien Sanglard state_ = State::kConnecting;
57*3f982cf4SFabien Sanglard }
58*3f982cf4SFabien Sanglard
OnConnected(uint64_t connection_id,uint64_t endpoint_id,std::unique_ptr<ProtocolConnection> protocol_connection)59*3f982cf4SFabien Sanglard void Connection::OnConnected(
60*3f982cf4SFabien Sanglard uint64_t connection_id,
61*3f982cf4SFabien Sanglard uint64_t endpoint_id,
62*3f982cf4SFabien Sanglard std::unique_ptr<ProtocolConnection> protocol_connection) {
63*3f982cf4SFabien Sanglard if (state_ != State::kConnecting) {
64*3f982cf4SFabien Sanglard return;
65*3f982cf4SFabien Sanglard }
66*3f982cf4SFabien Sanglard connection_id_ = connection_id;
67*3f982cf4SFabien Sanglard endpoint_id_ = endpoint_id;
68*3f982cf4SFabien Sanglard protocol_connection_ = std::move(protocol_connection);
69*3f982cf4SFabien Sanglard state_ = State::kConnected;
70*3f982cf4SFabien Sanglard delegate_->OnConnected();
71*3f982cf4SFabien Sanglard }
72*3f982cf4SFabien Sanglard
OnClosed()73*3f982cf4SFabien Sanglard bool Connection::OnClosed() {
74*3f982cf4SFabien Sanglard if (state_ != State::kConnecting && state_ != State::kConnected)
75*3f982cf4SFabien Sanglard return false;
76*3f982cf4SFabien Sanglard
77*3f982cf4SFabien Sanglard protocol_connection_.reset();
78*3f982cf4SFabien Sanglard state_ = State::kClosed;
79*3f982cf4SFabien Sanglard
80*3f982cf4SFabien Sanglard return true;
81*3f982cf4SFabien Sanglard }
82*3f982cf4SFabien Sanglard
OnClosedByError(Error cause)83*3f982cf4SFabien Sanglard void Connection::OnClosedByError(Error cause) {
84*3f982cf4SFabien Sanglard if (OnClosed()) {
85*3f982cf4SFabien Sanglard std::ostringstream stream;
86*3f982cf4SFabien Sanglard stream << cause;
87*3f982cf4SFabien Sanglard delegate_->OnError(stream.str());
88*3f982cf4SFabien Sanglard }
89*3f982cf4SFabien Sanglard }
90*3f982cf4SFabien Sanglard
OnClosedByRemote()91*3f982cf4SFabien Sanglard void Connection::OnClosedByRemote() {
92*3f982cf4SFabien Sanglard if (OnClosed())
93*3f982cf4SFabien Sanglard delegate_->OnClosedByRemote();
94*3f982cf4SFabien Sanglard }
95*3f982cf4SFabien Sanglard
OnTerminated()96*3f982cf4SFabien Sanglard void Connection::OnTerminated() {
97*3f982cf4SFabien Sanglard if (state_ == State::kTerminated)
98*3f982cf4SFabien Sanglard return;
99*3f982cf4SFabien Sanglard protocol_connection_.reset();
100*3f982cf4SFabien Sanglard state_ = State::kTerminated;
101*3f982cf4SFabien Sanglard delegate_->OnTerminated();
102*3f982cf4SFabien Sanglard }
103*3f982cf4SFabien Sanglard
SendString(absl::string_view message)104*3f982cf4SFabien Sanglard Error Connection::SendString(absl::string_view message) {
105*3f982cf4SFabien Sanglard if (state_ != State::kConnected)
106*3f982cf4SFabien Sanglard return Error::Code::kNoActiveConnection;
107*3f982cf4SFabien Sanglard
108*3f982cf4SFabien Sanglard msgs::PresentationConnectionMessage cbor_message;
109*3f982cf4SFabien Sanglard OSP_LOG_INFO << "sending '" << message << "' to (" << presentation_.id << ", "
110*3f982cf4SFabien Sanglard << connection_id_.value() << ")";
111*3f982cf4SFabien Sanglard cbor_message.connection_id = connection_id_.value();
112*3f982cf4SFabien Sanglard cbor_message.message.which =
113*3f982cf4SFabien Sanglard msgs::PresentationConnectionMessage::Message::Which::kString;
114*3f982cf4SFabien Sanglard
115*3f982cf4SFabien Sanglard new (&cbor_message.message.str) std::string(message);
116*3f982cf4SFabien Sanglard
117*3f982cf4SFabien Sanglard return WriteConnectionMessage(cbor_message, protocol_connection_.get());
118*3f982cf4SFabien Sanglard }
119*3f982cf4SFabien Sanglard
SendBinary(std::vector<uint8_t> && data)120*3f982cf4SFabien Sanglard Error Connection::SendBinary(std::vector<uint8_t>&& data) {
121*3f982cf4SFabien Sanglard if (state_ != State::kConnected)
122*3f982cf4SFabien Sanglard return Error::Code::kNoActiveConnection;
123*3f982cf4SFabien Sanglard
124*3f982cf4SFabien Sanglard msgs::PresentationConnectionMessage cbor_message;
125*3f982cf4SFabien Sanglard OSP_LOG_INFO << "sending " << data.size() << " bytes to (" << presentation_.id
126*3f982cf4SFabien Sanglard << ", " << connection_id_.value() << ")";
127*3f982cf4SFabien Sanglard cbor_message.connection_id = connection_id_.value();
128*3f982cf4SFabien Sanglard cbor_message.message.which =
129*3f982cf4SFabien Sanglard msgs::PresentationConnectionMessage::Message::Which::kBytes;
130*3f982cf4SFabien Sanglard
131*3f982cf4SFabien Sanglard new (&cbor_message.message.bytes) std::vector<uint8_t>(std::move(data));
132*3f982cf4SFabien Sanglard
133*3f982cf4SFabien Sanglard return WriteConnectionMessage(cbor_message, protocol_connection_.get());
134*3f982cf4SFabien Sanglard }
135*3f982cf4SFabien Sanglard
Close(CloseReason reason)136*3f982cf4SFabien Sanglard Error Connection::Close(CloseReason reason) {
137*3f982cf4SFabien Sanglard if (state_ == State::kClosed || state_ == State::kTerminated)
138*3f982cf4SFabien Sanglard return Error::Code::kAlreadyClosed;
139*3f982cf4SFabien Sanglard
140*3f982cf4SFabien Sanglard state_ = State::kClosed;
141*3f982cf4SFabien Sanglard protocol_connection_.reset();
142*3f982cf4SFabien Sanglard
143*3f982cf4SFabien Sanglard return parent_delegate_->CloseConnection(this, reason);
144*3f982cf4SFabien Sanglard }
145*3f982cf4SFabien Sanglard
Terminate(TerminationReason reason)146*3f982cf4SFabien Sanglard void Connection::Terminate(TerminationReason reason) {
147*3f982cf4SFabien Sanglard if (state_ == State::kTerminated)
148*3f982cf4SFabien Sanglard return;
149*3f982cf4SFabien Sanglard state_ = State::kTerminated;
150*3f982cf4SFabien Sanglard protocol_connection_.reset();
151*3f982cf4SFabien Sanglard parent_delegate_->OnPresentationTerminated(presentation_.id, reason);
152*3f982cf4SFabien Sanglard }
153*3f982cf4SFabien Sanglard
ConnectionManager(MessageDemuxer * demuxer)154*3f982cf4SFabien Sanglard ConnectionManager::ConnectionManager(MessageDemuxer* demuxer) {
155*3f982cf4SFabien Sanglard message_watch_ = demuxer->SetDefaultMessageTypeWatch(
156*3f982cf4SFabien Sanglard msgs::Type::kPresentationConnectionMessage, this);
157*3f982cf4SFabien Sanglard
158*3f982cf4SFabien Sanglard close_request_watch_ = demuxer->SetDefaultMessageTypeWatch(
159*3f982cf4SFabien Sanglard msgs::Type::kPresentationConnectionCloseRequest, this);
160*3f982cf4SFabien Sanglard
161*3f982cf4SFabien Sanglard close_event_watch_ = demuxer->SetDefaultMessageTypeWatch(
162*3f982cf4SFabien Sanglard msgs::Type::kPresentationConnectionCloseEvent, this);
163*3f982cf4SFabien Sanglard }
164*3f982cf4SFabien Sanglard
AddConnection(Connection * connection)165*3f982cf4SFabien Sanglard void ConnectionManager::AddConnection(Connection* connection) {
166*3f982cf4SFabien Sanglard auto emplace_result =
167*3f982cf4SFabien Sanglard connections_.emplace(connection->connection_id(), connection);
168*3f982cf4SFabien Sanglard
169*3f982cf4SFabien Sanglard OSP_DCHECK(emplace_result.second);
170*3f982cf4SFabien Sanglard }
171*3f982cf4SFabien Sanglard
RemoveConnection(Connection * connection)172*3f982cf4SFabien Sanglard void ConnectionManager::RemoveConnection(Connection* connection) {
173*3f982cf4SFabien Sanglard auto entry = connections_.find(connection->connection_id());
174*3f982cf4SFabien Sanglard if (entry != connections_.end()) {
175*3f982cf4SFabien Sanglard connections_.erase(entry);
176*3f982cf4SFabien Sanglard }
177*3f982cf4SFabien Sanglard }
178*3f982cf4SFabien Sanglard
179*3f982cf4SFabien Sanglard // TODO(jophba): add a utility object to track requests/responses
180*3f982cf4SFabien Sanglard // TODO(jophba): refine the RegisterWatch/OnStreamMessage API. We
181*3f982cf4SFabien Sanglard // should add a layer between the message logic and the parse/dispatch
182*3f982cf4SFabien Sanglard // logic, and remove the CBOR information from ConnectionManager.
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)183*3f982cf4SFabien Sanglard ErrorOr<size_t> ConnectionManager::OnStreamMessage(uint64_t endpoint_id,
184*3f982cf4SFabien Sanglard uint64_t connection_id,
185*3f982cf4SFabien Sanglard msgs::Type message_type,
186*3f982cf4SFabien Sanglard const uint8_t* buffer,
187*3f982cf4SFabien Sanglard size_t buffer_size,
188*3f982cf4SFabien Sanglard Clock::time_point now) {
189*3f982cf4SFabien Sanglard switch (message_type) {
190*3f982cf4SFabien Sanglard case msgs::Type::kPresentationConnectionMessage: {
191*3f982cf4SFabien Sanglard msgs::PresentationConnectionMessage message;
192*3f982cf4SFabien Sanglard ssize_t bytes_decoded = msgs::DecodePresentationConnectionMessage(
193*3f982cf4SFabien Sanglard buffer, buffer_size, &message);
194*3f982cf4SFabien Sanglard if (bytes_decoded < 0) {
195*3f982cf4SFabien Sanglard OSP_LOG_WARN << "presentation-connection-message parse error";
196*3f982cf4SFabien Sanglard return Error::Code::kParseError;
197*3f982cf4SFabien Sanglard }
198*3f982cf4SFabien Sanglard
199*3f982cf4SFabien Sanglard Connection* connection = GetConnection(message.connection_id);
200*3f982cf4SFabien Sanglard if (!connection) {
201*3f982cf4SFabien Sanglard return Error::Code::kItemNotFound;
202*3f982cf4SFabien Sanglard }
203*3f982cf4SFabien Sanglard
204*3f982cf4SFabien Sanglard switch (message.message.which) {
205*3f982cf4SFabien Sanglard case decltype(message.message.which)::kString:
206*3f982cf4SFabien Sanglard connection->get_delegate()->OnStringMessage(message.message.str);
207*3f982cf4SFabien Sanglard break;
208*3f982cf4SFabien Sanglard case decltype(message.message.which)::kBytes:
209*3f982cf4SFabien Sanglard connection->get_delegate()->OnBinaryMessage(message.message.bytes);
210*3f982cf4SFabien Sanglard break;
211*3f982cf4SFabien Sanglard default:
212*3f982cf4SFabien Sanglard OSP_LOG_WARN << "uninitialized message data in "
213*3f982cf4SFabien Sanglard "presentation-connection-message";
214*3f982cf4SFabien Sanglard break;
215*3f982cf4SFabien Sanglard }
216*3f982cf4SFabien Sanglard return bytes_decoded;
217*3f982cf4SFabien Sanglard }
218*3f982cf4SFabien Sanglard
219*3f982cf4SFabien Sanglard case msgs::Type::kPresentationConnectionCloseRequest: {
220*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseRequest request;
221*3f982cf4SFabien Sanglard ssize_t bytes_decoded = msgs::DecodePresentationConnectionCloseRequest(
222*3f982cf4SFabien Sanglard buffer, buffer_size, &request);
223*3f982cf4SFabien Sanglard if (bytes_decoded < 0) {
224*3f982cf4SFabien Sanglard OSP_LOG_WARN << "decode presentation-connection-close-request error: "
225*3f982cf4SFabien Sanglard << bytes_decoded;
226*3f982cf4SFabien Sanglard return Error::Code::kCborInvalidMessage;
227*3f982cf4SFabien Sanglard }
228*3f982cf4SFabien Sanglard
229*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseResponse response;
230*3f982cf4SFabien Sanglard response.request_id = request.request_id;
231*3f982cf4SFabien Sanglard
232*3f982cf4SFabien Sanglard Connection* connection = GetConnection(request.connection_id);
233*3f982cf4SFabien Sanglard if (connection) {
234*3f982cf4SFabien Sanglard response.result =
235*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseResponse_result::kSuccess;
236*3f982cf4SFabien Sanglard connection->OnClosedByRemote();
237*3f982cf4SFabien Sanglard } else {
238*3f982cf4SFabien Sanglard response.result = msgs::PresentationConnectionCloseResponse_result::
239*3f982cf4SFabien Sanglard kInvalidConnectionId;
240*3f982cf4SFabien Sanglard }
241*3f982cf4SFabien Sanglard
242*3f982cf4SFabien Sanglard std::unique_ptr<ProtocolConnection> protocol_connection =
243*3f982cf4SFabien Sanglard NetworkServiceManager::Get()
244*3f982cf4SFabien Sanglard ->GetProtocolConnectionServer()
245*3f982cf4SFabien Sanglard ->CreateProtocolConnection(endpoint_id);
246*3f982cf4SFabien Sanglard if (protocol_connection) {
247*3f982cf4SFabien Sanglard protocol_connection->WriteMessage(
248*3f982cf4SFabien Sanglard response, &msgs::EncodePresentationConnectionCloseResponse);
249*3f982cf4SFabien Sanglard }
250*3f982cf4SFabien Sanglard
251*3f982cf4SFabien Sanglard return (response.result ==
252*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseResponse_result::kSuccess)
253*3f982cf4SFabien Sanglard ? ErrorOr<size_t>(bytes_decoded)
254*3f982cf4SFabien Sanglard : Error::Code::kNoActiveConnection;
255*3f982cf4SFabien Sanglard }
256*3f982cf4SFabien Sanglard
257*3f982cf4SFabien Sanglard case msgs::Type::kPresentationConnectionCloseEvent: {
258*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseEvent event;
259*3f982cf4SFabien Sanglard ssize_t bytes_decoded = msgs::DecodePresentationConnectionCloseEvent(
260*3f982cf4SFabien Sanglard buffer, buffer_size, &event);
261*3f982cf4SFabien Sanglard if (bytes_decoded < 0) {
262*3f982cf4SFabien Sanglard OSP_LOG_WARN << "decode presentation-connection-close-event error: "
263*3f982cf4SFabien Sanglard << bytes_decoded;
264*3f982cf4SFabien Sanglard return Error::Code::kParseError;
265*3f982cf4SFabien Sanglard }
266*3f982cf4SFabien Sanglard
267*3f982cf4SFabien Sanglard Connection* connection = GetConnection(event.connection_id);
268*3f982cf4SFabien Sanglard if (!connection) {
269*3f982cf4SFabien Sanglard return Error::Code::kNoActiveConnection;
270*3f982cf4SFabien Sanglard }
271*3f982cf4SFabien Sanglard
272*3f982cf4SFabien Sanglard connection->OnClosedByRemote();
273*3f982cf4SFabien Sanglard return bytes_decoded;
274*3f982cf4SFabien Sanglard }
275*3f982cf4SFabien Sanglard
276*3f982cf4SFabien Sanglard // TODO(jophba): The spec says to close the connection if we get a message
277*3f982cf4SFabien Sanglard // we don't understand. Figure out how to honor the spec here.
278*3f982cf4SFabien Sanglard default:
279*3f982cf4SFabien Sanglard return Error::Code::kUnknownMessageType;
280*3f982cf4SFabien Sanglard }
281*3f982cf4SFabien Sanglard }
282*3f982cf4SFabien Sanglard
GetConnection(uint64_t connection_id)283*3f982cf4SFabien Sanglard Connection* ConnectionManager::GetConnection(uint64_t connection_id) {
284*3f982cf4SFabien Sanglard auto entry = connections_.find(connection_id);
285*3f982cf4SFabien Sanglard if (entry != connections_.end()) {
286*3f982cf4SFabien Sanglard return entry->second;
287*3f982cf4SFabien Sanglard }
288*3f982cf4SFabien Sanglard
289*3f982cf4SFabien Sanglard OSP_DVLOG << "unknown ID: " << connection_id;
290*3f982cf4SFabien Sanglard return nullptr;
291*3f982cf4SFabien Sanglard }
292*3f982cf4SFabien Sanglard
293*3f982cf4SFabien Sanglard } // namespace osp
294*3f982cf4SFabien Sanglard } // namespace openscreen
295