xref: /aosp_15_r20/external/openscreen/osp/impl/presentation/presentation_receiver.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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_receiver.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <memory>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include "osp/impl/presentation/presentation_common.h"
11*3f982cf4SFabien Sanglard #include "osp/msgs/osp_messages.h"
12*3f982cf4SFabien Sanglard #include "osp/public/message_demuxer.h"
13*3f982cf4SFabien Sanglard #include "osp/public/network_service_manager.h"
14*3f982cf4SFabien Sanglard #include "osp/public/protocol_connection_server.h"
15*3f982cf4SFabien Sanglard #include "platform/api/time.h"
16*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
17*3f982cf4SFabien Sanglard #include "util/trace_logging.h"
18*3f982cf4SFabien Sanglard 
19*3f982cf4SFabien Sanglard namespace openscreen {
20*3f982cf4SFabien Sanglard namespace osp {
21*3f982cf4SFabien Sanglard namespace {
22*3f982cf4SFabien Sanglard 
GetEventCloseReason(Connection::CloseReason reason)23*3f982cf4SFabien Sanglard msgs::PresentationConnectionCloseEvent_reason GetEventCloseReason(
24*3f982cf4SFabien Sanglard     Connection::CloseReason reason) {
25*3f982cf4SFabien Sanglard   switch (reason) {
26*3f982cf4SFabien Sanglard     case Connection::CloseReason::kDiscarded:
27*3f982cf4SFabien Sanglard       return msgs::PresentationConnectionCloseEvent_reason::
28*3f982cf4SFabien Sanglard           kConnectionObjectDiscarded;
29*3f982cf4SFabien Sanglard 
30*3f982cf4SFabien Sanglard     case Connection::CloseReason::kError:
31*3f982cf4SFabien Sanglard       return msgs::PresentationConnectionCloseEvent_reason::
32*3f982cf4SFabien Sanglard           kUnrecoverableErrorWhileSendingOrReceivingMessage;
33*3f982cf4SFabien Sanglard 
34*3f982cf4SFabien Sanglard     case Connection::CloseReason::kClosed:  // fallthrough
35*3f982cf4SFabien Sanglard     default:
36*3f982cf4SFabien Sanglard       return msgs::PresentationConnectionCloseEvent_reason::kCloseMethodCalled;
37*3f982cf4SFabien Sanglard   }
38*3f982cf4SFabien Sanglard }
39*3f982cf4SFabien Sanglard 
GetEventTerminationReason(TerminationReason reason)40*3f982cf4SFabien Sanglard msgs::PresentationTerminationEvent_reason GetEventTerminationReason(
41*3f982cf4SFabien Sanglard     TerminationReason reason) {
42*3f982cf4SFabien Sanglard   switch (reason) {
43*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverUserTerminated:
44*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::
45*3f982cf4SFabien Sanglard           kUserTerminatedViaReceiver;
46*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverShuttingDown:
47*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::kReceiverPoweringDown;
48*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverPresentationUnloaded:
49*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::
50*3f982cf4SFabien Sanglard           kReceiverAttemptedToNavigate;
51*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverPresentationReplaced:
52*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::
53*3f982cf4SFabien Sanglard           kReceiverReplacedPresentation;
54*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverIdleTooLong:
55*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::kReceiverIdleTooLong;
56*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverError:
57*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::kReceiverCrashed;
58*3f982cf4SFabien Sanglard     case TerminationReason::kReceiverTerminateCalled:
59*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::
60*3f982cf4SFabien Sanglard           kReceiverCalledTerminate;
61*3f982cf4SFabien Sanglard     default:
62*3f982cf4SFabien Sanglard       return msgs::PresentationTerminationEvent_reason::kUnknown;
63*3f982cf4SFabien Sanglard   }
64*3f982cf4SFabien Sanglard }
65*3f982cf4SFabien Sanglard 
WritePresentationInitiationResponse(const msgs::PresentationStartResponse & response,ProtocolConnection * connection)66*3f982cf4SFabien Sanglard Error WritePresentationInitiationResponse(
67*3f982cf4SFabien Sanglard     const msgs::PresentationStartResponse& response,
68*3f982cf4SFabien Sanglard     ProtocolConnection* connection) {
69*3f982cf4SFabien Sanglard   return connection->WriteMessage(response,
70*3f982cf4SFabien Sanglard                                   msgs::EncodePresentationStartResponse);
71*3f982cf4SFabien Sanglard }
72*3f982cf4SFabien Sanglard 
WritePresentationConnectionOpenResponse(const msgs::PresentationConnectionOpenResponse & response,ProtocolConnection * connection)73*3f982cf4SFabien Sanglard Error WritePresentationConnectionOpenResponse(
74*3f982cf4SFabien Sanglard     const msgs::PresentationConnectionOpenResponse& response,
75*3f982cf4SFabien Sanglard     ProtocolConnection* connection) {
76*3f982cf4SFabien Sanglard   return connection->WriteMessage(
77*3f982cf4SFabien Sanglard       response, msgs::EncodePresentationConnectionOpenResponse);
78*3f982cf4SFabien Sanglard }
79*3f982cf4SFabien Sanglard 
WritePresentationTerminationEvent(const msgs::PresentationTerminationEvent & event,ProtocolConnection * connection)80*3f982cf4SFabien Sanglard Error WritePresentationTerminationEvent(
81*3f982cf4SFabien Sanglard     const msgs::PresentationTerminationEvent& event,
82*3f982cf4SFabien Sanglard     ProtocolConnection* connection) {
83*3f982cf4SFabien Sanglard   return connection->WriteMessage(event,
84*3f982cf4SFabien Sanglard                                   msgs::EncodePresentationTerminationEvent);
85*3f982cf4SFabien Sanglard }
86*3f982cf4SFabien Sanglard 
WritePresentationTerminationResponse(const msgs::PresentationTerminationResponse & response,ProtocolConnection * connection)87*3f982cf4SFabien Sanglard Error WritePresentationTerminationResponse(
88*3f982cf4SFabien Sanglard     const msgs::PresentationTerminationResponse& response,
89*3f982cf4SFabien Sanglard     ProtocolConnection* connection) {
90*3f982cf4SFabien Sanglard   return connection->WriteMessage(response,
91*3f982cf4SFabien Sanglard                                   msgs::EncodePresentationTerminationResponse);
92*3f982cf4SFabien Sanglard }
93*3f982cf4SFabien Sanglard 
WritePresentationUrlAvailabilityResponse(const msgs::PresentationUrlAvailabilityResponse & response,ProtocolConnection * connection)94*3f982cf4SFabien Sanglard Error WritePresentationUrlAvailabilityResponse(
95*3f982cf4SFabien Sanglard     const msgs::PresentationUrlAvailabilityResponse& response,
96*3f982cf4SFabien Sanglard     ProtocolConnection* connection) {
97*3f982cf4SFabien Sanglard   return connection->WriteMessage(
98*3f982cf4SFabien Sanglard       response, msgs::EncodePresentationUrlAvailabilityResponse);
99*3f982cf4SFabien Sanglard }
100*3f982cf4SFabien Sanglard 
101*3f982cf4SFabien Sanglard }  // namespace
102*3f982cf4SFabien Sanglard 
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)103*3f982cf4SFabien Sanglard ErrorOr<size_t> Receiver::OnStreamMessage(uint64_t endpoint_id,
104*3f982cf4SFabien Sanglard                                           uint64_t connection_id,
105*3f982cf4SFabien Sanglard                                           msgs::Type message_type,
106*3f982cf4SFabien Sanglard                                           const uint8_t* buffer,
107*3f982cf4SFabien Sanglard                                           size_t buffer_size,
108*3f982cf4SFabien Sanglard                                           Clock::time_point now) {
109*3f982cf4SFabien Sanglard   TRACE_SCOPED(TraceCategory::kPresentation, "Receiver::OnStreamMessage");
110*3f982cf4SFabien Sanglard   switch (message_type) {
111*3f982cf4SFabien Sanglard     case msgs::Type::kPresentationUrlAvailabilityRequest: {
112*3f982cf4SFabien Sanglard       TRACE_SCOPED(TraceCategory::kPresentation,
113*3f982cf4SFabien Sanglard                    "kPresentationUrlAvailabilityRequest");
114*3f982cf4SFabien Sanglard       OSP_VLOG << "got presentation-url-availability-request";
115*3f982cf4SFabien Sanglard       msgs::PresentationUrlAvailabilityRequest request;
116*3f982cf4SFabien Sanglard       ssize_t decode_result = msgs::DecodePresentationUrlAvailabilityRequest(
117*3f982cf4SFabien Sanglard           buffer, buffer_size, &request);
118*3f982cf4SFabien Sanglard       if (decode_result < 0) {
119*3f982cf4SFabien Sanglard         OSP_LOG_WARN << "Presentation-url-availability-request parse error: "
120*3f982cf4SFabien Sanglard                      << decode_result;
121*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(Error::Code::kParseError);
122*3f982cf4SFabien Sanglard         return Error::Code::kParseError;
123*3f982cf4SFabien Sanglard       }
124*3f982cf4SFabien Sanglard 
125*3f982cf4SFabien Sanglard       msgs::PresentationUrlAvailabilityResponse response;
126*3f982cf4SFabien Sanglard       response.request_id = request.request_id;
127*3f982cf4SFabien Sanglard 
128*3f982cf4SFabien Sanglard       response.url_availabilities = delegate_->OnUrlAvailabilityRequest(
129*3f982cf4SFabien Sanglard           request.watch_id, request.watch_duration, std::move(request.urls));
130*3f982cf4SFabien Sanglard       msgs::CborEncodeBuffer buffer;
131*3f982cf4SFabien Sanglard 
132*3f982cf4SFabien Sanglard       WritePresentationUrlAvailabilityResponse(
133*3f982cf4SFabien Sanglard           response, GetProtocolConnection(endpoint_id).get());
134*3f982cf4SFabien Sanglard       return decode_result;
135*3f982cf4SFabien Sanglard     }
136*3f982cf4SFabien Sanglard 
137*3f982cf4SFabien Sanglard     case msgs::Type::kPresentationStartRequest: {
138*3f982cf4SFabien Sanglard       TRACE_SCOPED(TraceCategory::kPresentation, "kPresentationStartRequest");
139*3f982cf4SFabien Sanglard       OSP_VLOG << "got presentation-start-request";
140*3f982cf4SFabien Sanglard       msgs::PresentationStartRequest request;
141*3f982cf4SFabien Sanglard       const ssize_t result =
142*3f982cf4SFabien Sanglard           msgs::DecodePresentationStartRequest(buffer, buffer_size, &request);
143*3f982cf4SFabien Sanglard       if (result < 0) {
144*3f982cf4SFabien Sanglard         OSP_LOG_WARN << "Presentation-initiation-request parse error: "
145*3f982cf4SFabien Sanglard                      << result;
146*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(Error::Code::kParseError);
147*3f982cf4SFabien Sanglard         return Error::Code::kParseError;
148*3f982cf4SFabien Sanglard       }
149*3f982cf4SFabien Sanglard 
150*3f982cf4SFabien Sanglard       OSP_LOG_INFO << "Got an initiation request for: " << request.url;
151*3f982cf4SFabien Sanglard 
152*3f982cf4SFabien Sanglard       PresentationID presentation_id(std::move(request.presentation_id));
153*3f982cf4SFabien Sanglard       if (!presentation_id) {
154*3f982cf4SFabien Sanglard         msgs::PresentationStartResponse response;
155*3f982cf4SFabien Sanglard         response.request_id = request.request_id;
156*3f982cf4SFabien Sanglard         response.result =
157*3f982cf4SFabien Sanglard             msgs::PresentationStartResponse_result::kInvalidPresentationId;
158*3f982cf4SFabien Sanglard         Error write_error = WritePresentationInitiationResponse(
159*3f982cf4SFabien Sanglard             response, GetProtocolConnection(endpoint_id).get());
160*3f982cf4SFabien Sanglard 
161*3f982cf4SFabien Sanglard         if (!write_error.ok()) {
162*3f982cf4SFabien Sanglard           TRACE_SET_RESULT(write_error);
163*3f982cf4SFabien Sanglard           return write_error;
164*3f982cf4SFabien Sanglard         }
165*3f982cf4SFabien Sanglard 
166*3f982cf4SFabien Sanglard         return result;
167*3f982cf4SFabien Sanglard       }
168*3f982cf4SFabien Sanglard 
169*3f982cf4SFabien Sanglard       auto& response_list = queued_responses_[presentation_id];
170*3f982cf4SFabien Sanglard       QueuedResponse queued_response{
171*3f982cf4SFabien Sanglard           /* .type = */ QueuedResponse::Type::kInitiation,
172*3f982cf4SFabien Sanglard           /* .request_id = */ request.request_id,
173*3f982cf4SFabien Sanglard           /* .connection_id = */ this->GetNextConnectionId(),
174*3f982cf4SFabien Sanglard           /* .endpoint_id = */ endpoint_id};
175*3f982cf4SFabien Sanglard       response_list.push_back(std::move(queued_response));
176*3f982cf4SFabien Sanglard 
177*3f982cf4SFabien Sanglard       const bool starting = delegate_->StartPresentation(
178*3f982cf4SFabien Sanglard           Connection::PresentationInfo{presentation_id, request.url},
179*3f982cf4SFabien Sanglard           endpoint_id, request.headers);
180*3f982cf4SFabien Sanglard 
181*3f982cf4SFabien Sanglard       if (starting)
182*3f982cf4SFabien Sanglard         return result;
183*3f982cf4SFabien Sanglard 
184*3f982cf4SFabien Sanglard       queued_responses_.erase(presentation_id);
185*3f982cf4SFabien Sanglard       msgs::PresentationStartResponse response;
186*3f982cf4SFabien Sanglard       response.request_id = request.request_id;
187*3f982cf4SFabien Sanglard       response.result = msgs::PresentationStartResponse_result::kUnknownError;
188*3f982cf4SFabien Sanglard       Error write_error = WritePresentationInitiationResponse(
189*3f982cf4SFabien Sanglard           response, GetProtocolConnection(endpoint_id).get());
190*3f982cf4SFabien Sanglard       if (!write_error.ok()) {
191*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(write_error);
192*3f982cf4SFabien Sanglard         return write_error;
193*3f982cf4SFabien Sanglard       }
194*3f982cf4SFabien Sanglard 
195*3f982cf4SFabien Sanglard       return result;
196*3f982cf4SFabien Sanglard     }
197*3f982cf4SFabien Sanglard 
198*3f982cf4SFabien Sanglard     case msgs::Type::kPresentationConnectionOpenRequest: {
199*3f982cf4SFabien Sanglard       TRACE_SCOPED(TraceCategory::kPresentation,
200*3f982cf4SFabien Sanglard                    "kPresentationConnectionOpenRequest");
201*3f982cf4SFabien Sanglard       OSP_VLOG << "Got a presentation-connection-open-request";
202*3f982cf4SFabien Sanglard       msgs::PresentationConnectionOpenRequest request;
203*3f982cf4SFabien Sanglard       const ssize_t result = msgs::DecodePresentationConnectionOpenRequest(
204*3f982cf4SFabien Sanglard           buffer, buffer_size, &request);
205*3f982cf4SFabien Sanglard       if (result < 0) {
206*3f982cf4SFabien Sanglard         OSP_LOG_WARN << "Presentation-connection-open-request parse error: "
207*3f982cf4SFabien Sanglard                      << result;
208*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(Error::Code::kParseError);
209*3f982cf4SFabien Sanglard         return Error::Code::kParseError;
210*3f982cf4SFabien Sanglard       }
211*3f982cf4SFabien Sanglard 
212*3f982cf4SFabien Sanglard       PresentationID presentation_id(std::move(request.presentation_id));
213*3f982cf4SFabien Sanglard 
214*3f982cf4SFabien Sanglard       // TODO(jophba): add logic to queue presentation connection open
215*3f982cf4SFabien Sanglard       // (and terminate connection)
216*3f982cf4SFabien Sanglard       // requests to check against when a presentation starts, in case
217*3f982cf4SFabien Sanglard       // we get a request right before the beginning of the presentation.
218*3f982cf4SFabien Sanglard       if (!presentation_id || started_presentations_.find(presentation_id) ==
219*3f982cf4SFabien Sanglard                                   started_presentations_.end()) {
220*3f982cf4SFabien Sanglard         msgs::PresentationConnectionOpenResponse response;
221*3f982cf4SFabien Sanglard         response.request_id = request.request_id;
222*3f982cf4SFabien Sanglard         response.result = msgs::PresentationConnectionOpenResponse_result::
223*3f982cf4SFabien Sanglard             kInvalidPresentationId;
224*3f982cf4SFabien Sanglard         Error write_error = WritePresentationConnectionOpenResponse(
225*3f982cf4SFabien Sanglard             response, GetProtocolConnection(endpoint_id).get());
226*3f982cf4SFabien Sanglard         if (!write_error.ok()) {
227*3f982cf4SFabien Sanglard           TRACE_SET_RESULT(write_error);
228*3f982cf4SFabien Sanglard           return write_error;
229*3f982cf4SFabien Sanglard         }
230*3f982cf4SFabien Sanglard 
231*3f982cf4SFabien Sanglard         return result;
232*3f982cf4SFabien Sanglard       }
233*3f982cf4SFabien Sanglard 
234*3f982cf4SFabien Sanglard       // TODO(btolsch): We would also check that connection_id isn't already
235*3f982cf4SFabien Sanglard       // requested/in use but since the spec has already shifted to a
236*3f982cf4SFabien Sanglard       // receiver-chosen connection ID, we'll ignore that until we change our
237*3f982cf4SFabien Sanglard       // CDDL messages.
238*3f982cf4SFabien Sanglard       std::vector<QueuedResponse>& responses =
239*3f982cf4SFabien Sanglard           queued_responses_[presentation_id];
240*3f982cf4SFabien Sanglard       responses.emplace_back(
241*3f982cf4SFabien Sanglard           QueuedResponse{QueuedResponse::Type::kConnection, request.request_id,
242*3f982cf4SFabien Sanglard                          this->GetNextConnectionId(), endpoint_id});
243*3f982cf4SFabien Sanglard       bool connecting = delegate_->ConnectToPresentation(
244*3f982cf4SFabien Sanglard           request.request_id, presentation_id, endpoint_id);
245*3f982cf4SFabien Sanglard       if (connecting)
246*3f982cf4SFabien Sanglard         return result;
247*3f982cf4SFabien Sanglard 
248*3f982cf4SFabien Sanglard       responses.pop_back();
249*3f982cf4SFabien Sanglard       if (responses.empty())
250*3f982cf4SFabien Sanglard         queued_responses_.erase(presentation_id);
251*3f982cf4SFabien Sanglard 
252*3f982cf4SFabien Sanglard       msgs::PresentationConnectionOpenResponse response;
253*3f982cf4SFabien Sanglard       response.request_id = request.request_id;
254*3f982cf4SFabien Sanglard       response.result =
255*3f982cf4SFabien Sanglard           msgs::PresentationConnectionOpenResponse_result::kUnknownError;
256*3f982cf4SFabien Sanglard       Error write_error = WritePresentationConnectionOpenResponse(
257*3f982cf4SFabien Sanglard           response, GetProtocolConnection(endpoint_id).get());
258*3f982cf4SFabien Sanglard       if (!write_error.ok()) {
259*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(write_error);
260*3f982cf4SFabien Sanglard         return write_error;
261*3f982cf4SFabien Sanglard       }
262*3f982cf4SFabien Sanglard 
263*3f982cf4SFabien Sanglard       return result;
264*3f982cf4SFabien Sanglard     }
265*3f982cf4SFabien Sanglard 
266*3f982cf4SFabien Sanglard     case msgs::Type::kPresentationTerminationRequest: {
267*3f982cf4SFabien Sanglard       TRACE_SCOPED(TraceCategory::kPresentation,
268*3f982cf4SFabien Sanglard                    "kPresentationTerminationRequest");
269*3f982cf4SFabien Sanglard       OSP_VLOG << "got presentation-termination-request";
270*3f982cf4SFabien Sanglard       msgs::PresentationTerminationRequest request;
271*3f982cf4SFabien Sanglard       const ssize_t result = msgs::DecodePresentationTerminationRequest(
272*3f982cf4SFabien Sanglard           buffer, buffer_size, &request);
273*3f982cf4SFabien Sanglard       if (result < 0) {
274*3f982cf4SFabien Sanglard         OSP_LOG_WARN << "Presentation-termination-request parse error: "
275*3f982cf4SFabien Sanglard                      << result;
276*3f982cf4SFabien Sanglard         TRACE_SET_RESULT(Error::Code::kParseError);
277*3f982cf4SFabien Sanglard         return Error::Code::kParseError;
278*3f982cf4SFabien Sanglard       }
279*3f982cf4SFabien Sanglard 
280*3f982cf4SFabien Sanglard       PresentationID presentation_id(std::move(request.presentation_id));
281*3f982cf4SFabien Sanglard       OSP_LOG_INFO << "Got termination request for: " << presentation_id;
282*3f982cf4SFabien Sanglard 
283*3f982cf4SFabien Sanglard       auto presentation_entry = started_presentations_.find(presentation_id);
284*3f982cf4SFabien Sanglard       if (presentation_id &&
285*3f982cf4SFabien Sanglard           presentation_entry != started_presentations_.end()) {
286*3f982cf4SFabien Sanglard         TerminationReason reason =
287*3f982cf4SFabien Sanglard             (request.reason == msgs::PresentationTerminationRequest_reason::
288*3f982cf4SFabien Sanglard                                    kUserTerminatedViaController)
289*3f982cf4SFabien Sanglard                 ? TerminationReason::kControllerTerminateCalled
290*3f982cf4SFabien Sanglard                 : TerminationReason::kControllerUserTerminated;
291*3f982cf4SFabien Sanglard         presentation_entry->second.terminate_request_id = request.request_id;
292*3f982cf4SFabien Sanglard         delegate_->TerminatePresentation(presentation_id, reason);
293*3f982cf4SFabien Sanglard 
294*3f982cf4SFabien Sanglard         msgs::PresentationTerminationResponse response;
295*3f982cf4SFabien Sanglard         response.request_id = request.request_id;
296*3f982cf4SFabien Sanglard         response.result = msgs::PresentationTerminationResponse_result::
297*3f982cf4SFabien Sanglard             kInvalidPresentationId;
298*3f982cf4SFabien Sanglard         Error write_error = WritePresentationTerminationResponse(
299*3f982cf4SFabien Sanglard             response, GetProtocolConnection(endpoint_id).get());
300*3f982cf4SFabien Sanglard         if (!write_error.ok()) {
301*3f982cf4SFabien Sanglard           TRACE_SET_RESULT(write_error);
302*3f982cf4SFabien Sanglard           return write_error;
303*3f982cf4SFabien Sanglard         }
304*3f982cf4SFabien Sanglard         return result;
305*3f982cf4SFabien Sanglard       }
306*3f982cf4SFabien Sanglard 
307*3f982cf4SFabien Sanglard       TerminationReason reason =
308*3f982cf4SFabien Sanglard           (request.reason == msgs::PresentationTerminationRequest_reason::
309*3f982cf4SFabien Sanglard                                  kControllerCalledTerminate)
310*3f982cf4SFabien Sanglard               ? TerminationReason::kControllerTerminateCalled
311*3f982cf4SFabien Sanglard               : TerminationReason::kControllerUserTerminated;
312*3f982cf4SFabien Sanglard       presentation_entry->second.terminate_request_id = request.request_id;
313*3f982cf4SFabien Sanglard       delegate_->TerminatePresentation(presentation_id, reason);
314*3f982cf4SFabien Sanglard 
315*3f982cf4SFabien Sanglard       return result;
316*3f982cf4SFabien Sanglard     }
317*3f982cf4SFabien Sanglard 
318*3f982cf4SFabien Sanglard     default:
319*3f982cf4SFabien Sanglard       TRACE_SET_RESULT(Error::Code::kUnknownMessageType);
320*3f982cf4SFabien Sanglard       return Error::Code::kUnknownMessageType;
321*3f982cf4SFabien Sanglard   }
322*3f982cf4SFabien Sanglard }
323*3f982cf4SFabien Sanglard 
324*3f982cf4SFabien Sanglard // TODO(crbug.com/openscreen/31): Remove singletons in the embedder API and
325*3f982cf4SFabien Sanglard // protocol implementation layers and in presentation_connection, as well as
326*3f982cf4SFabien Sanglard // unit tests. static
Get()327*3f982cf4SFabien Sanglard Receiver* Receiver::Get() {
328*3f982cf4SFabien Sanglard   static Receiver& receiver = *new Receiver();
329*3f982cf4SFabien Sanglard   return &receiver;
330*3f982cf4SFabien Sanglard }
331*3f982cf4SFabien Sanglard 
Init()332*3f982cf4SFabien Sanglard void Receiver::Init() {
333*3f982cf4SFabien Sanglard   if (!connection_manager_) {
334*3f982cf4SFabien Sanglard     connection_manager_ =
335*3f982cf4SFabien Sanglard         std::make_unique<ConnectionManager>(GetServerDemuxer());
336*3f982cf4SFabien Sanglard   }
337*3f982cf4SFabien Sanglard }
338*3f982cf4SFabien Sanglard 
Deinit()339*3f982cf4SFabien Sanglard void Receiver::Deinit() {
340*3f982cf4SFabien Sanglard   connection_manager_.reset();
341*3f982cf4SFabien Sanglard }
342*3f982cf4SFabien Sanglard 
SetReceiverDelegate(ReceiverDelegate * delegate)343*3f982cf4SFabien Sanglard void Receiver::SetReceiverDelegate(ReceiverDelegate* delegate) {
344*3f982cf4SFabien Sanglard   OSP_DCHECK(!delegate_ || !delegate);
345*3f982cf4SFabien Sanglard   delegate_ = delegate;
346*3f982cf4SFabien Sanglard 
347*3f982cf4SFabien Sanglard   MessageDemuxer* demuxer = GetServerDemuxer();
348*3f982cf4SFabien Sanglard   if (delegate_) {
349*3f982cf4SFabien Sanglard     availability_watch_ = demuxer->SetDefaultMessageTypeWatch(
350*3f982cf4SFabien Sanglard         msgs::Type::kPresentationUrlAvailabilityRequest, this);
351*3f982cf4SFabien Sanglard     initiation_watch_ = demuxer->SetDefaultMessageTypeWatch(
352*3f982cf4SFabien Sanglard         msgs::Type::kPresentationStartRequest, this);
353*3f982cf4SFabien Sanglard     connection_watch_ = demuxer->SetDefaultMessageTypeWatch(
354*3f982cf4SFabien Sanglard         msgs::Type::kPresentationConnectionOpenRequest, this);
355*3f982cf4SFabien Sanglard     return;
356*3f982cf4SFabien Sanglard   }
357*3f982cf4SFabien Sanglard 
358*3f982cf4SFabien Sanglard   StopWatching(&availability_watch_);
359*3f982cf4SFabien Sanglard   StopWatching(&initiation_watch_);
360*3f982cf4SFabien Sanglard   StopWatching(&connection_watch_);
361*3f982cf4SFabien Sanglard 
362*3f982cf4SFabien Sanglard   std::vector<std::string> presentations_to_remove(
363*3f982cf4SFabien Sanglard       started_presentations_.size());
364*3f982cf4SFabien Sanglard   for (auto& it : started_presentations_) {
365*3f982cf4SFabien Sanglard     presentations_to_remove.push_back(it.first);
366*3f982cf4SFabien Sanglard   }
367*3f982cf4SFabien Sanglard 
368*3f982cf4SFabien Sanglard   for (auto& presentation_id : presentations_to_remove) {
369*3f982cf4SFabien Sanglard     OnPresentationTerminated(presentation_id,
370*3f982cf4SFabien Sanglard                              TerminationReason::kReceiverShuttingDown);
371*3f982cf4SFabien Sanglard   }
372*3f982cf4SFabien Sanglard }
373*3f982cf4SFabien Sanglard 
OnPresentationStarted(const std::string & presentation_id,Connection * connection,ResponseResult result)374*3f982cf4SFabien Sanglard Error Receiver::OnPresentationStarted(const std::string& presentation_id,
375*3f982cf4SFabien Sanglard                                       Connection* connection,
376*3f982cf4SFabien Sanglard                                       ResponseResult result) {
377*3f982cf4SFabien Sanglard   auto queued_responses_entry = queued_responses_.find(presentation_id);
378*3f982cf4SFabien Sanglard   if (queued_responses_entry == queued_responses_.end())
379*3f982cf4SFabien Sanglard     return Error::Code::kNoStartedPresentation;
380*3f982cf4SFabien Sanglard 
381*3f982cf4SFabien Sanglard   auto& responses = queued_responses_entry->second;
382*3f982cf4SFabien Sanglard   if ((responses.size() != 1) ||
383*3f982cf4SFabien Sanglard       (responses.front().type != QueuedResponse::Type::kInitiation)) {
384*3f982cf4SFabien Sanglard     return Error::Code::kPresentationAlreadyStarted;
385*3f982cf4SFabien Sanglard   }
386*3f982cf4SFabien Sanglard 
387*3f982cf4SFabien Sanglard   QueuedResponse& initiation_response = responses.front();
388*3f982cf4SFabien Sanglard   msgs::PresentationStartResponse response;
389*3f982cf4SFabien Sanglard   response.request_id = initiation_response.request_id;
390*3f982cf4SFabien Sanglard   auto protocol_connection =
391*3f982cf4SFabien Sanglard       GetProtocolConnection(initiation_response.endpoint_id);
392*3f982cf4SFabien Sanglard   auto* raw_protocol_connection_ptr = protocol_connection.get();
393*3f982cf4SFabien Sanglard 
394*3f982cf4SFabien Sanglard   OSP_VLOG << "presentation started with protocol_connection id: "
395*3f982cf4SFabien Sanglard            << protocol_connection->id();
396*3f982cf4SFabien Sanglard   if (result != ResponseResult::kSuccess) {
397*3f982cf4SFabien Sanglard     response.result = msgs::PresentationStartResponse_result::kUnknownError;
398*3f982cf4SFabien Sanglard 
399*3f982cf4SFabien Sanglard     queued_responses_.erase(queued_responses_entry);
400*3f982cf4SFabien Sanglard     return WritePresentationInitiationResponse(response,
401*3f982cf4SFabien Sanglard                                                raw_protocol_connection_ptr);
402*3f982cf4SFabien Sanglard   }
403*3f982cf4SFabien Sanglard 
404*3f982cf4SFabien Sanglard   response.result = msgs::PresentationStartResponse_result::kSuccess;
405*3f982cf4SFabien Sanglard   response.connection_id = connection->connection_id();
406*3f982cf4SFabien Sanglard 
407*3f982cf4SFabien Sanglard   Presentation& presentation = started_presentations_[presentation_id];
408*3f982cf4SFabien Sanglard   presentation.endpoint_id = initiation_response.endpoint_id;
409*3f982cf4SFabien Sanglard   connection->OnConnected(initiation_response.connection_id,
410*3f982cf4SFabien Sanglard                           initiation_response.endpoint_id,
411*3f982cf4SFabien Sanglard                           std::move(protocol_connection));
412*3f982cf4SFabien Sanglard   presentation.connections.push_back(connection);
413*3f982cf4SFabien Sanglard   connection_manager_->AddConnection(connection);
414*3f982cf4SFabien Sanglard 
415*3f982cf4SFabien Sanglard   presentation.terminate_watch = GetServerDemuxer()->WatchMessageType(
416*3f982cf4SFabien Sanglard       initiation_response.endpoint_id,
417*3f982cf4SFabien Sanglard       msgs::Type::kPresentationTerminationRequest, this);
418*3f982cf4SFabien Sanglard 
419*3f982cf4SFabien Sanglard   queued_responses_.erase(queued_responses_entry);
420*3f982cf4SFabien Sanglard   return WritePresentationInitiationResponse(response,
421*3f982cf4SFabien Sanglard                                              raw_protocol_connection_ptr);
422*3f982cf4SFabien Sanglard }
423*3f982cf4SFabien Sanglard 
OnConnectionCreated(uint64_t request_id,Connection * connection,ResponseResult result)424*3f982cf4SFabien Sanglard Error Receiver::OnConnectionCreated(uint64_t request_id,
425*3f982cf4SFabien Sanglard                                     Connection* connection,
426*3f982cf4SFabien Sanglard                                     ResponseResult result) {
427*3f982cf4SFabien Sanglard   const auto presentation_id = connection->presentation_info().id;
428*3f982cf4SFabien Sanglard 
429*3f982cf4SFabien Sanglard   ErrorOr<QueuedResponseIterator> connection_response =
430*3f982cf4SFabien Sanglard       GetQueuedResponse(presentation_id, request_id);
431*3f982cf4SFabien Sanglard   if (connection_response.is_error()) {
432*3f982cf4SFabien Sanglard     return connection_response.error();
433*3f982cf4SFabien Sanglard   }
434*3f982cf4SFabien Sanglard   connection->OnConnected(
435*3f982cf4SFabien Sanglard       connection_response.value()->connection_id,
436*3f982cf4SFabien Sanglard       connection_response.value()->endpoint_id,
437*3f982cf4SFabien Sanglard       NetworkServiceManager::Get()
438*3f982cf4SFabien Sanglard           ->GetProtocolConnectionServer()
439*3f982cf4SFabien Sanglard           ->CreateProtocolConnection(connection_response.value()->endpoint_id));
440*3f982cf4SFabien Sanglard 
441*3f982cf4SFabien Sanglard   started_presentations_[presentation_id].connections.push_back(connection);
442*3f982cf4SFabien Sanglard   connection_manager_->AddConnection(connection);
443*3f982cf4SFabien Sanglard 
444*3f982cf4SFabien Sanglard   msgs::PresentationConnectionOpenResponse response;
445*3f982cf4SFabien Sanglard   response.request_id = request_id;
446*3f982cf4SFabien Sanglard   response.result = msgs::PresentationConnectionOpenResponse_result::kSuccess;
447*3f982cf4SFabien Sanglard   response.connection_id = connection->connection_id();
448*3f982cf4SFabien Sanglard 
449*3f982cf4SFabien Sanglard   auto protocol_connection =
450*3f982cf4SFabien Sanglard       GetProtocolConnection(connection_response.value()->endpoint_id);
451*3f982cf4SFabien Sanglard 
452*3f982cf4SFabien Sanglard   WritePresentationConnectionOpenResponse(response, protocol_connection.get());
453*3f982cf4SFabien Sanglard 
454*3f982cf4SFabien Sanglard   DeleteQueuedResponse(presentation_id, connection_response.value());
455*3f982cf4SFabien Sanglard   return Error::None();
456*3f982cf4SFabien Sanglard }
457*3f982cf4SFabien Sanglard 
CloseConnection(Connection * connection,Connection::CloseReason reason)458*3f982cf4SFabien Sanglard Error Receiver::CloseConnection(Connection* connection,
459*3f982cf4SFabien Sanglard                                 Connection::CloseReason reason) {
460*3f982cf4SFabien Sanglard   std::unique_ptr<ProtocolConnection> protocol_connection =
461*3f982cf4SFabien Sanglard       GetProtocolConnection(connection->endpoint_id());
462*3f982cf4SFabien Sanglard 
463*3f982cf4SFabien Sanglard   if (!protocol_connection)
464*3f982cf4SFabien Sanglard     return Error::Code::kNoActiveConnection;
465*3f982cf4SFabien Sanglard 
466*3f982cf4SFabien Sanglard   msgs::PresentationConnectionCloseEvent event;
467*3f982cf4SFabien Sanglard   event.connection_id = connection->connection_id();
468*3f982cf4SFabien Sanglard   event.reason = GetEventCloseReason(reason);
469*3f982cf4SFabien Sanglard   event.has_error_message = false;
470*3f982cf4SFabien Sanglard   msgs::CborEncodeBuffer buffer;
471*3f982cf4SFabien Sanglard   return protocol_connection->WriteMessage(
472*3f982cf4SFabien Sanglard       event, msgs::EncodePresentationConnectionCloseEvent);
473*3f982cf4SFabien Sanglard }
474*3f982cf4SFabien Sanglard 
OnPresentationTerminated(const std::string & presentation_id,TerminationReason reason)475*3f982cf4SFabien Sanglard Error Receiver::OnPresentationTerminated(const std::string& presentation_id,
476*3f982cf4SFabien Sanglard                                          TerminationReason reason) {
477*3f982cf4SFabien Sanglard   auto presentation_entry = started_presentations_.find(presentation_id);
478*3f982cf4SFabien Sanglard   if (presentation_entry == started_presentations_.end())
479*3f982cf4SFabien Sanglard     return Error::Code::kNoStartedPresentation;
480*3f982cf4SFabien Sanglard 
481*3f982cf4SFabien Sanglard   Presentation& presentation = presentation_entry->second;
482*3f982cf4SFabien Sanglard   presentation.terminate_watch = MessageDemuxer::MessageWatch();
483*3f982cf4SFabien Sanglard   std::unique_ptr<ProtocolConnection> protocol_connection =
484*3f982cf4SFabien Sanglard       GetProtocolConnection(presentation.endpoint_id);
485*3f982cf4SFabien Sanglard 
486*3f982cf4SFabien Sanglard   if (!protocol_connection)
487*3f982cf4SFabien Sanglard     return Error::Code::kNoActiveConnection;
488*3f982cf4SFabien Sanglard 
489*3f982cf4SFabien Sanglard   for (auto* connection : presentation.connections)
490*3f982cf4SFabien Sanglard     connection->OnTerminated();
491*3f982cf4SFabien Sanglard 
492*3f982cf4SFabien Sanglard   if (presentation.terminate_request_id) {
493*3f982cf4SFabien Sanglard     // TODO(btolsch): Also timeout if this point isn't reached.
494*3f982cf4SFabien Sanglard     msgs::PresentationTerminationResponse response;
495*3f982cf4SFabien Sanglard     response.request_id = presentation.terminate_request_id;
496*3f982cf4SFabien Sanglard     response.result = msgs::PresentationTerminationResponse_result::kSuccess;
497*3f982cf4SFabien Sanglard     started_presentations_.erase(presentation_entry);
498*3f982cf4SFabien Sanglard     return WritePresentationTerminationResponse(response,
499*3f982cf4SFabien Sanglard                                                 protocol_connection.get());
500*3f982cf4SFabien Sanglard   }
501*3f982cf4SFabien Sanglard 
502*3f982cf4SFabien Sanglard   msgs::PresentationTerminationEvent event;
503*3f982cf4SFabien Sanglard   event.presentation_id = presentation_id;
504*3f982cf4SFabien Sanglard   event.reason = GetEventTerminationReason(reason);
505*3f982cf4SFabien Sanglard   started_presentations_.erase(presentation_entry);
506*3f982cf4SFabien Sanglard   return WritePresentationTerminationEvent(event, protocol_connection.get());
507*3f982cf4SFabien Sanglard }
508*3f982cf4SFabien Sanglard 
OnConnectionDestroyed(Connection * connection)509*3f982cf4SFabien Sanglard void Receiver::OnConnectionDestroyed(Connection* connection) {
510*3f982cf4SFabien Sanglard   auto presentation_entry =
511*3f982cf4SFabien Sanglard       started_presentations_.find(connection->presentation_info().id);
512*3f982cf4SFabien Sanglard   if (presentation_entry == started_presentations_.end())
513*3f982cf4SFabien Sanglard     return;
514*3f982cf4SFabien Sanglard 
515*3f982cf4SFabien Sanglard   std::vector<Connection*>& connections =
516*3f982cf4SFabien Sanglard       presentation_entry->second.connections;
517*3f982cf4SFabien Sanglard 
518*3f982cf4SFabien Sanglard   auto past_the_end =
519*3f982cf4SFabien Sanglard       std::remove(connections.begin(), connections.end(), connection);
520*3f982cf4SFabien Sanglard   // An additional call to "erase" is necessary to actually adjust the size
521*3f982cf4SFabien Sanglard   // of the vector.
522*3f982cf4SFabien Sanglard   connections.erase(past_the_end, connections.end());
523*3f982cf4SFabien Sanglard 
524*3f982cf4SFabien Sanglard   connection_manager_->RemoveConnection(connection);
525*3f982cf4SFabien Sanglard }
526*3f982cf4SFabien Sanglard 
527*3f982cf4SFabien Sanglard Receiver::Receiver() = default;
528*3f982cf4SFabien Sanglard 
529*3f982cf4SFabien Sanglard Receiver::~Receiver() = default;
530*3f982cf4SFabien Sanglard 
DeleteQueuedResponse(const std::string & presentation_id,Receiver::QueuedResponseIterator response)531*3f982cf4SFabien Sanglard void Receiver::DeleteQueuedResponse(const std::string& presentation_id,
532*3f982cf4SFabien Sanglard                                     Receiver::QueuedResponseIterator response) {
533*3f982cf4SFabien Sanglard   auto entry = queued_responses_.find(presentation_id);
534*3f982cf4SFabien Sanglard   entry->second.erase(response);
535*3f982cf4SFabien Sanglard   if (entry->second.empty())
536*3f982cf4SFabien Sanglard     queued_responses_.erase(entry);
537*3f982cf4SFabien Sanglard }
538*3f982cf4SFabien Sanglard 
GetQueuedResponse(const std::string & presentation_id,uint64_t request_id) const539*3f982cf4SFabien Sanglard ErrorOr<Receiver::QueuedResponseIterator> Receiver::GetQueuedResponse(
540*3f982cf4SFabien Sanglard     const std::string& presentation_id,
541*3f982cf4SFabien Sanglard     uint64_t request_id) const {
542*3f982cf4SFabien Sanglard   auto entry = queued_responses_.find(presentation_id);
543*3f982cf4SFabien Sanglard   if (entry == queued_responses_.end()) {
544*3f982cf4SFabien Sanglard     OSP_LOG_WARN << "connection created for unknown request";
545*3f982cf4SFabien Sanglard     return Error::Code::kUnknownRequestId;
546*3f982cf4SFabien Sanglard   }
547*3f982cf4SFabien Sanglard 
548*3f982cf4SFabien Sanglard   const std::vector<QueuedResponse>& responses = entry->second;
549*3f982cf4SFabien Sanglard   Receiver::QueuedResponseIterator it =
550*3f982cf4SFabien Sanglard       std::find_if(responses.begin(), responses.end(),
551*3f982cf4SFabien Sanglard                    [request_id](const QueuedResponse& response) {
552*3f982cf4SFabien Sanglard                      return response.request_id == request_id;
553*3f982cf4SFabien Sanglard                    });
554*3f982cf4SFabien Sanglard 
555*3f982cf4SFabien Sanglard   if (it == responses.end()) {
556*3f982cf4SFabien Sanglard     OSP_LOG_WARN << "connection created for unknown request";
557*3f982cf4SFabien Sanglard     return Error::Code::kUnknownRequestId;
558*3f982cf4SFabien Sanglard   }
559*3f982cf4SFabien Sanglard 
560*3f982cf4SFabien Sanglard   return it;
561*3f982cf4SFabien Sanglard }
562*3f982cf4SFabien Sanglard 
GetNextConnectionId()563*3f982cf4SFabien Sanglard uint64_t Receiver::GetNextConnectionId() {
564*3f982cf4SFabien Sanglard   static uint64_t request_id = 0;
565*3f982cf4SFabien Sanglard   return request_id++;
566*3f982cf4SFabien Sanglard }
567*3f982cf4SFabien Sanglard 
568*3f982cf4SFabien Sanglard }  // namespace osp
569*3f982cf4SFabien Sanglard }  // namespace openscreen
570