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 #include "cast/common/channel/cast_socket_message_port.h"
6 
7 #include <utility>
8 
9 #include "cast/common/channel/message_util.h"
10 #include "cast/common/channel/proto/cast_channel.pb.h"
11 #include "cast/common/channel/virtual_connection.h"
12 
13 namespace openscreen {
14 namespace cast {
15 
CastSocketMessagePort(VirtualConnectionRouter * router)16 CastSocketMessagePort::CastSocketMessagePort(VirtualConnectionRouter* router)
17     : router_(router) {}
18 
~CastSocketMessagePort()19 CastSocketMessagePort::~CastSocketMessagePort() {
20   ResetClient();
21 }
22 
23 // NOTE: we assume here that this message port is already the client for
24 // the passed in socket, so leave the socket's client unchanged. However,
25 // since sockets should map one to one with receiver sessions, we reset our
26 // client. The consumer of this message port should call SetClient with the new
27 // message port client after setting the socket.
SetSocket(WeakPtr<CastSocket> socket)28 void CastSocketMessagePort::SetSocket(WeakPtr<CastSocket> socket) {
29   ResetClient();
30   socket_ = socket;
31 }
32 
GetSocketId()33 int CastSocketMessagePort::GetSocketId() {
34   return ToCastSocketId(socket_.get());
35 }
36 
SetClient(MessagePort::Client * client,std::string client_sender_id)37 void CastSocketMessagePort::SetClient(MessagePort::Client* client,
38                                       std::string client_sender_id) {
39   ResetClient();
40 
41   client_ = client;
42   client_sender_id_ = std::move(client_sender_id);
43   router_->AddHandlerForLocalId(client_sender_id_, this);
44 }
45 
ResetClient()46 void CastSocketMessagePort::ResetClient() {
47   if (!client_) {
48     return;
49   }
50 
51   client_ = nullptr;
52   router_->RemoveHandlerForLocalId(client_sender_id_);
53   router_->RemoveConnectionsByLocalId(client_sender_id_);
54   client_sender_id_.clear();
55 }
56 
PostMessage(const std::string & destination_sender_id,const std::string & message_namespace,const std::string & message)57 void CastSocketMessagePort::PostMessage(
58     const std::string& destination_sender_id,
59     const std::string& message_namespace,
60     const std::string& message) {
61   if (!client_) {
62     OSP_DLOG_WARN << "Not posting message due to nullptr client_";
63     return;
64   }
65 
66   if (!socket_) {
67     client_->OnError(Error::Code::kAlreadyClosed);
68     return;
69   }
70 
71   VirtualConnection connection{client_sender_id_, destination_sender_id,
72                                socket_->socket_id()};
73   if (!router_->GetConnectionData(connection)) {
74     router_->AddConnection(connection, VirtualConnection::AssociatedData{});
75   }
76 
77   const Error send_error = router_->Send(
78       std::move(connection), MakeSimpleUTF8Message(message_namespace, message));
79   if (!send_error.ok()) {
80     client_->OnError(std::move(send_error));
81   }
82 }
83 
OnMessage(VirtualConnectionRouter * router,CastSocket * socket,::cast::channel::CastMessage message)84 void CastSocketMessagePort::OnMessage(VirtualConnectionRouter* router,
85                                       CastSocket* socket,
86                                       ::cast::channel::CastMessage message) {
87   OSP_DCHECK(router == router_);
88   OSP_DCHECK(!socket || socket_.get() == socket);
89 
90   // Message ports are for specific virtual connections, and do not pass-through
91   // broadcasts.
92   if (message.destination_id() == kBroadcastId) {
93     return;
94   }
95 
96   OSP_DVLOG << "Received a cast socket message";
97   if (!client_) {
98     OSP_DLOG_WARN << "Dropping message due to nullptr client_";
99     return;
100   }
101 
102   client_->OnMessage(message.source_id(), message.namespace_(),
103                      message.payload_utf8());
104 }
105 
106 }  // namespace cast
107 }  // namespace openscreen
108