1 // Copyright 2020 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 #include "cast/receiver/application_agent.h"
6 
7 #include <utility>
8 
9 #include "cast/common/channel/message_util.h"
10 #include "cast/common/channel/virtual_connection.h"
11 #include "cast/common/public/cast_socket.h"
12 #include "platform/base/tls_credentials.h"
13 #include "platform/base/tls_listen_options.h"
14 #include "util/json/json_serialization.h"
15 #include "util/osp_logging.h"
16 
17 namespace openscreen {
18 namespace cast {
19 namespace {
20 
21 // Parses the given string as a JSON object. If the parse fails, an empty object
22 // is returned.
ParseAsObject(absl::string_view value)23 Json::Value ParseAsObject(absl::string_view value) {
24   ErrorOr<Json::Value> parsed = json::Parse(value);
25   if (parsed.is_value() && parsed.value().isObject()) {
26     return std::move(parsed.value());
27   }
28   return Json::Value(Json::objectValue);
29 }
30 
31 // Returns true if the type field in |object| is set to the given |type|.
HasType(const Json::Value & object,CastMessageType type)32 bool HasType(const Json::Value& object, CastMessageType type) {
33   OSP_DCHECK(object.isObject());
34   const Json::Value& value =
35       object.get(kMessageKeyType, Json::Value::nullSingleton());
36   return value.isString() && value.asString() == CastMessageTypeToString(type);
37 }
38 
39 // Returns the first app ID for the given |app|, or the empty string if there is
40 // none.
GetFirstAppId(ApplicationAgent::Application * app)41 std::string GetFirstAppId(ApplicationAgent::Application* app) {
42   const auto& app_ids = app->GetAppIds();
43   return app_ids.empty() ? std::string() : app_ids.front();
44 }
45 
46 }  // namespace
47 
ApplicationAgent(TaskRunner * task_runner,DeviceAuthNamespaceHandler::CredentialsProvider * credentials_provider)48 ApplicationAgent::ApplicationAgent(
49     TaskRunner* task_runner,
50     DeviceAuthNamespaceHandler::CredentialsProvider* credentials_provider)
51     : task_runner_(task_runner),
52       auth_handler_(credentials_provider),
53       connection_handler_(&router_, this),
54       message_port_(&router_) {
55   router_.AddHandlerForLocalId(kPlatformReceiverId, this);
56 }
57 
~ApplicationAgent()58 ApplicationAgent::~ApplicationAgent() {
59   OSP_DCHECK(task_runner_->IsRunningOnTaskRunner());
60 
61   idle_screen_app_ = nullptr;  // Prevent re-launching the idle screen app.
62   SwitchToApplication({}, {}, nullptr);
63 
64   router_.RemoveHandlerForLocalId(kPlatformReceiverId);
65 }
66 
RegisterApplication(Application * app,bool auto_launch_for_idle_screen)67 void ApplicationAgent::RegisterApplication(Application* app,
68                                            bool auto_launch_for_idle_screen) {
69   OSP_DCHECK(app);
70 
71   for (const std::string& app_id : app->GetAppIds()) {
72     OSP_DCHECK(!app_id.empty());
73     const auto insert_result = registered_applications_.insert({app_id, app});
74     // The insert must not fail (prior entry for same key).
75     OSP_DCHECK(insert_result.second);
76   }
77 
78   if (auto_launch_for_idle_screen) {
79     OSP_DCHECK(!idle_screen_app_);
80     idle_screen_app_ = app;
81     // Launch the idle screen app, if no app was running.
82     if (!launched_app_) {
83       GoIdle();
84     }
85   }
86 }
87 
UnregisterApplication(Application * app)88 void ApplicationAgent::UnregisterApplication(Application* app) {
89   for (auto it = registered_applications_.begin();
90        it != registered_applications_.end();) {
91     if (it->second == app) {
92       it = registered_applications_.erase(it);
93     } else {
94       ++it;
95     }
96   }
97 
98   if (idle_screen_app_ == app) {
99     idle_screen_app_ = nullptr;
100   }
101 
102   if (launched_app_ == app) {
103     GoIdle();
104   }
105 }
106 
StopApplicationIfRunning(Application * app)107 void ApplicationAgent::StopApplicationIfRunning(Application* app) {
108   if (launched_app_ == app) {
109     GoIdle();
110   }
111 }
112 
OnConnected(ReceiverSocketFactory * factory,const IPEndpoint & endpoint,std::unique_ptr<CastSocket> socket)113 void ApplicationAgent::OnConnected(ReceiverSocketFactory* factory,
114                                    const IPEndpoint& endpoint,
115                                    std::unique_ptr<CastSocket> socket) {
116   router_.TakeSocket(this, std::move(socket));
117 }
118 
OnError(ReceiverSocketFactory * factory,Error error)119 void ApplicationAgent::OnError(ReceiverSocketFactory* factory, Error error) {
120   OSP_LOG_ERROR << "Cast agent received socket factory error: " << error;
121 }
122 
OnMessage(VirtualConnectionRouter * router,CastSocket * socket,::cast::channel::CastMessage message)123 void ApplicationAgent::OnMessage(VirtualConnectionRouter* router,
124                                  CastSocket* socket,
125                                  ::cast::channel::CastMessage message) {
126   if (message_port_.GetSocketId() == ToCastSocketId(socket) &&
127       !message_port_.client_sender_id().empty() &&
128       message_port_.client_sender_id() == message.destination_id()) {
129     OSP_DCHECK(message_port_.client_sender_id() != kPlatformReceiverId);
130     message_port_.OnMessage(router, socket, std::move(message));
131     return;
132   }
133 
134   if (message.destination_id() != kPlatformReceiverId &&
135       message.destination_id() != kBroadcastId) {
136     return;  // Message not for us.
137   }
138 
139   const std::string& ns = message.namespace_();
140   if (ns == kAuthNamespace) {
141     auth_handler_.OnMessage(router, socket, std::move(message));
142     return;
143   }
144 
145   const Json::Value request = ParseAsObject(message.payload_utf8());
146   Json::Value response;
147   if (ns == kHeartbeatNamespace) {
148     if (HasType(request, CastMessageType::kPing)) {
149       response = HandlePing();
150     }
151   } else if (ns == kReceiverNamespace) {
152     if (request[kMessageKeyRequestId].isNull()) {
153       response = HandleInvalidCommand(request);
154     } else if (HasType(request, CastMessageType::kGetAppAvailability)) {
155       response = HandleGetAppAvailability(request);
156     } else if (HasType(request, CastMessageType::kGetStatus)) {
157       response = HandleGetStatus(request);
158     } else if (HasType(request, CastMessageType::kLaunch)) {
159       response = HandleLaunch(request, socket);
160     } else if (HasType(request, CastMessageType::kStop)) {
161       response = HandleStop(request);
162     } else {
163       response = HandleInvalidCommand(request);
164     }
165   } else {
166     // Ignore messages for all other namespaces.
167   }
168 
169   if (!response.empty()) {
170     router_.Send(VirtualConnection{message.destination_id(),
171                                    message.source_id(), ToCastSocketId(socket)},
172                  MakeSimpleUTF8Message(ns, json::Stringify(response).value()));
173   }
174 }
175 
IsConnectionAllowed(const VirtualConnection & virtual_conn) const176 bool ApplicationAgent::IsConnectionAllowed(
177     const VirtualConnection& virtual_conn) const {
178   if (virtual_conn.local_id == kPlatformReceiverId) {
179     return true;
180   }
181   if (!launched_app_ || message_port_.client_sender_id().empty()) {
182     // No app currently launched. Or, there is a launched app, but it did not
183     // call MessagePort::SetClient() to indicate it wants messages routed to it.
184     return false;
185   }
186   return virtual_conn.local_id == message_port_.client_sender_id();
187 }
188 
OnClose(CastSocket * socket)189 void ApplicationAgent::OnClose(CastSocket* socket) {
190   if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
191     OSP_VLOG << "Cast agent socket closed.";
192     GoIdle();
193   }
194 }
195 
OnError(CastSocket * socket,Error error)196 void ApplicationAgent::OnError(CastSocket* socket, Error error) {
197   if (message_port_.GetSocketId() == ToCastSocketId(socket)) {
198     OSP_LOG_ERROR << "Cast agent received socket error: " << error;
199     GoIdle();
200   }
201 }
202 
HandlePing()203 Json::Value ApplicationAgent::HandlePing() {
204   Json::Value response;
205   response[kMessageKeyType] = CastMessageTypeToString(CastMessageType::kPong);
206   return response;
207 }
208 
HandleGetAppAvailability(const Json::Value & request)209 Json::Value ApplicationAgent::HandleGetAppAvailability(
210     const Json::Value& request) {
211   Json::Value response;
212   const Json::Value& app_ids = request[kMessageKeyAppId];
213   if (app_ids.isArray()) {
214     response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
215     response[kMessageKeyResponseType] = request[kMessageKeyType];
216     Json::Value& availability = response[kMessageKeyAvailability];
217     for (const Json::Value& app_id : app_ids) {
218       if (app_id.isString()) {
219         const auto app_id_str = app_id.asString();
220         availability[app_id_str] = registered_applications_.count(app_id_str)
221                                        ? kMessageValueAppAvailable
222                                        : kMessageValueAppUnavailable;
223       }
224     }
225   }
226   return response;
227 }
228 
HandleGetStatus(const Json::Value & request)229 Json::Value ApplicationAgent::HandleGetStatus(const Json::Value& request) {
230   Json::Value response;
231   PopulateReceiverStatus(&response);
232   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
233   return response;
234 }
235 
HandleLaunch(const Json::Value & request,CastSocket * socket)236 Json::Value ApplicationAgent::HandleLaunch(const Json::Value& request,
237                                            CastSocket* socket) {
238   const Json::Value& app_id = request[kMessageKeyAppId];
239   Error error;
240   if (app_id.isString() && !app_id.asString().empty()) {
241     error = SwitchToApplication(app_id.asString(),
242                                 request[kMessageKeyAppParams], socket);
243   } else {
244     error = Error(Error::Code::kParameterInvalid, kMessageValueBadParameter);
245   }
246   if (!error.ok()) {
247     Json::Value response;
248     response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
249     response[kMessageKeyType] =
250         CastMessageTypeToString(CastMessageType::kLaunchError);
251     response[kMessageKeyReason] = error.message();
252     return response;
253   }
254 
255   // Note: No reply is sent. Instead, the requestor will get a RECEIVER_STATUS
256   // broadcast message from SwitchToApplication(), which is how it will see that
257   // the launch succeeded.
258   return {};
259 }
260 
HandleStop(const Json::Value & request)261 Json::Value ApplicationAgent::HandleStop(const Json::Value& request) {
262   const Json::Value& session_id = request[kMessageKeySessionId];
263   if (session_id.isNull()) {
264     GoIdle();
265     return {};
266   }
267 
268   if (session_id.isString() && launched_app_ &&
269       session_id.asString() == launched_app_->GetSessionId()) {
270     GoIdle();
271     return {};
272   }
273 
274   Json::Value response;
275   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
276   response[kMessageKeyType] =
277       CastMessageTypeToString(CastMessageType::kInvalidRequest);
278   response[kMessageKeyReason] = kMessageValueInvalidSessionId;
279   return response;
280 }
281 
HandleInvalidCommand(const Json::Value & request)282 Json::Value ApplicationAgent::HandleInvalidCommand(const Json::Value& request) {
283   Json::Value response;
284   if (request[kMessageKeyRequestId].isNull()) {
285     return response;
286   }
287   response[kMessageKeyRequestId] = request[kMessageKeyRequestId];
288   response[kMessageKeyType] =
289       CastMessageTypeToString(CastMessageType::kInvalidRequest);
290   response[kMessageKeyReason] = kMessageValueInvalidCommand;
291   return response;
292 }
293 
SwitchToApplication(std::string app_id,const Json::Value & app_params,CastSocket * socket)294 Error ApplicationAgent::SwitchToApplication(std::string app_id,
295                                             const Json::Value& app_params,
296                                             CastSocket* socket) {
297   Error error = Error::Code::kNone;
298   Application* desired_app = nullptr;
299   Application* fallback_app = nullptr;
300   if (!app_id.empty()) {
301     const auto it = registered_applications_.find(app_id);
302     if (it != registered_applications_.end()) {
303       desired_app = it->second;
304       if (desired_app != idle_screen_app_) {
305         fallback_app = idle_screen_app_;
306       }
307     } else {
308       return Error(Error::Code::kItemNotFound, kMessageValueNotFound);
309     }
310   }
311 
312   if (launched_app_ == desired_app) {
313     return error;
314   }
315 
316   if (launched_app_) {
317     launched_app_->Stop();
318     message_port_.SetSocket({});
319     launched_app_ = nullptr;
320     launched_via_app_id_ = {};
321   }
322 
323   if (desired_app) {
324     if (socket) {
325       message_port_.SetSocket(socket->GetWeakPtr());
326     }
327     if (desired_app->Launch(app_id, app_params, &message_port_)) {
328       launched_app_ = desired_app;
329       launched_via_app_id_ = std::move(app_id);
330     } else {
331       error = Error(Error::Code::kUnknownError, kMessageValueSystemError);
332       message_port_.SetSocket({});
333     }
334   }
335 
336   if (!launched_app_ && fallback_app) {
337     app_id = GetFirstAppId(fallback_app);
338     if (fallback_app->Launch(app_id, {}, &message_port_)) {
339       launched_app_ = fallback_app;
340       launched_via_app_id_ = std::move(app_id);
341     }
342   }
343 
344   BroadcastReceiverStatus();
345 
346   return error;
347 }
348 
GoIdle()349 void ApplicationAgent::GoIdle() {
350   std::string app_id;
351   if (idle_screen_app_) {
352     app_id = GetFirstAppId(idle_screen_app_);
353   }
354   SwitchToApplication(app_id, {}, nullptr);
355 }
356 
PopulateReceiverStatus(Json::Value * out)357 void ApplicationAgent::PopulateReceiverStatus(Json::Value* out) {
358   Json::Value& message = *out;
359   message[kMessageKeyType] =
360       CastMessageTypeToString(CastMessageType::kReceiverStatus);
361   Json::Value& status = message[kMessageKeyStatus];
362 
363   if (launched_app_) {
364     Json::Value& details = status[kMessageKeyApplications][0];
365     // If the Application can send/receive messages, the destination for such
366     // messages is provided here, in |transportId|. However, the other end must
367     // first set up the virtual connection by issuing a CONNECT request.
368     // Otherwise, messages will not get routed to the Application by the
369     // VirtualConnectionRouter.
370     if (!message_port_.client_sender_id().empty()) {
371       details[kMessageKeyTransportId] = message_port_.client_sender_id();
372     }
373     details[kMessageKeySessionId] = launched_app_->GetSessionId();
374     details[kMessageKeyAppId] = launched_via_app_id_;
375     details[kMessageKeyUniversalAppId] = launched_via_app_id_;
376     details[kMessageKeyDisplayName] = launched_app_->GetDisplayName();
377     details[kMessageKeyIsIdleScreen] = (launched_app_ == idle_screen_app_);
378     details[kMessageKeyLaunchedFromCloud] = false;
379     std::vector<std::string> app_namespaces =
380         launched_app_->GetSupportedNamespaces();
381     Json::Value& namespaces =
382         (details[kMessageKeyNamespaces] = Json::Value(Json::arrayValue));
383     for (int i = 0, count = app_namespaces.size(); i < count; ++i) {
384       namespaces[i][kMessageKeyName] = std::move(app_namespaces[i]);
385     }
386   }
387 
388   status[kMessageKeyUserEq] = Json::Value(Json::objectValue);
389 
390   // Indicate a fixed 100% volume level.
391   Json::Value& volume = status[kMessageKeyVolume];
392   volume[kMessageKeyControlType] = kMessageValueAttenuation;
393   volume[kMessageKeyLevel] = 1.0;
394   volume[kMessageKeyMuted] = false;
395   volume[kMessageKeyStepInterval] = 0.05;
396 }
397 
BroadcastReceiverStatus()398 void ApplicationAgent::BroadcastReceiverStatus() {
399   Json::Value message;
400   PopulateReceiverStatus(&message);
401   message[kMessageKeyRequestId] = Json::Value(0);  // Indicates no requestor.
402   router_.BroadcastFromLocalPeer(
403       kPlatformReceiverId,
404       MakeSimpleUTF8Message(kReceiverNamespace,
405                             json::Stringify(message).value()));
406 }
407 
408 ApplicationAgent::Application::~Application() = default;
409 
410 }  // namespace cast
411 }  // namespace openscreen
412