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