2 * Copyright © 2012 Canonical Ltd.
3 * © 2016 Simon Fels <morphis@gravedo.de>
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License version 3,
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Authored by: Alan Griffiths <alan@octopull.co.uk>
20 #include "anbox/rpc/channel.h"
21 #include "anbox/common/variable_length_array.h"
22 #include "anbox/network/message_sender.h"
23 #include "anbox/rpc/constants.h"
24 #include "anbox/rpc/pending_call_cache.h"
26 #include "anbox_rpc.pb.h"
30 Channel::Channel(const std::shared_ptr<PendingCallCache> &pending_calls,
31 const std::shared_ptr<network::MessageSender> &sender)
32 : pending_calls_(pending_calls), sender_(sender) {}
34 Channel::~Channel() {}
36 void Channel::call_method(std::string const &method_name,
37 google::protobuf::MessageLite const *parameters,
38 google::protobuf::MessageLite *response,
39 google::protobuf::Closure *complete) {
40 auto const &invocation = invocation_for(method_name, parameters);
41 pending_calls_->save_completion_details(invocation, response, complete);
42 send_message(MessageType::invocation, invocation);
45 void Channel::send_event(google::protobuf::MessageLite const &event) {
46 VariableLengthArray<2048> buffer{static_cast<size_t>(event.ByteSize())};
47 event.SerializeWithCachedSizesToArray(buffer.data());
49 anbox::protobuf::rpc::Result response;
50 response.add_events(buffer.data(), buffer.size());
52 send_message(MessageType::response, response);
55 protobuf::rpc::Invocation Channel::invocation_for(
56 std::string const &method_name,
57 google::protobuf::MessageLite const *request) {
58 anbox::VariableLengthArray<2048> buffer{
59 static_cast<size_t>(request->ByteSize())};
61 request->SerializeWithCachedSizesToArray(buffer.data());
63 anbox::protobuf::rpc::Invocation invoke;
65 invoke.set_id(next_id());
66 invoke.set_method_name(method_name);
67 invoke.set_parameters(buffer.data(), buffer.size());
68 invoke.set_protocol_version(1);
73 void Channel::send_message(const std::uint8_t &type,
74 google::protobuf::MessageLite const &message) {
75 const size_t size = message.ByteSize();
76 const unsigned char header_bytes[header_size] = {
77 static_cast<unsigned char>((size >>16) & 0xff),
78 static_cast<unsigned char>((size >> 8) & 0xff),
79 static_cast<unsigned char>((size >> 0) & 0xff), type,
82 std::vector<std::uint8_t> send_buffer(sizeof(header_bytes) + size);
83 std::copy(header_bytes, header_bytes + sizeof(header_bytes),
85 message.SerializeToArray(send_buffer.data() + sizeof(header_bytes), size);
88 std::lock_guard<std::mutex> lock(write_mutex_);
89 sender_->send(reinterpret_cast<const char *>(send_buffer.data()),
91 } catch (std::runtime_error const &) {
92 notify_disconnected();
97 void Channel::notify_disconnected() { pending_calls_->force_completion(); }
99 std::uint32_t Channel::next_id() {
100 static std::uint32_t next_message_id = 0;
101 return next_message_id++;