2 * Copyright © 2013-2014 Canonical Ltd.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
19 #include "anbox/network/base_socket_messenger.h"
20 #include "anbox/common/variable_length_array.h"
21 #include "anbox/logger.h"
23 #include <boost/throw_exception.hpp>
30 namespace bs = boost::system;
31 namespace ba = boost::asio;
34 /// Buffers need to be big enough to support messages
35 unsigned int const serialization_buffer_size = 2048;
40 template <typename stream_protocol>
41 BaseSocketMessenger<stream_protocol>::BaseSocketMessenger() {}
43 template <typename stream_protocol>
44 BaseSocketMessenger<stream_protocol>::BaseSocketMessenger(
45 std::shared_ptr<ba::basic_stream_socket<stream_protocol>> const& socket) {
49 template <typename stream_protocol>
50 BaseSocketMessenger<stream_protocol>::~BaseSocketMessenger() {}
52 template <typename stream_protocol>
53 void BaseSocketMessenger<stream_protocol>::setup(
54 std::shared_ptr<ba::basic_stream_socket<stream_protocol>> const& s) {
56 socket_fd = anbox::Fd{IntOwnedFd{socket->native_handle()}};
57 socket->non_blocking(true);
58 boost::asio::socket_base::send_buffer_size option(64 * 1024);
59 socket->set_option(option);
62 template <typename stream_protocol>
63 Credentials BaseSocketMessenger<stream_protocol>::creds() const {
65 socklen_t cl = sizeof(cr);
67 auto status = getsockopt(socket_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl);
70 BOOST_THROW_EXCEPTION(
71 std::runtime_error("Failed to query client socket credentials"));
73 return {cr.pid, cr.uid, cr.gid};
76 template <typename stream_protocol>
77 ssize_t BaseSocketMessenger<stream_protocol>::send_raw(char const* data,
79 VariableLengthArray<serialization_buffer_size> whole_message{length};
80 std::copy(data, data + length, whole_message.data());
82 std::unique_lock<std::mutex> lg(message_lock);
83 return ::send(socket_fd, data, length, MSG_NOSIGNAL);
86 template <typename stream_protocol>
87 void BaseSocketMessenger<stream_protocol>::send(char const* data,
89 VariableLengthArray<serialization_buffer_size> whole_message{length};
90 std::copy(data, data + length, whole_message.data());
94 std::unique_lock<std::mutex> lg(message_lock);
95 ba::write(*socket, ba::buffer(whole_message.data(), whole_message.size()),
96 boost::asio::transfer_all());
97 } catch (const boost::system::system_error& err) {
98 if (err.code() == boost::asio::error::try_again) continue;
105 template <typename stream_protocol>
106 void BaseSocketMessenger<stream_protocol>::async_receive_msg(
107 AnboxReadHandler const& handler, ba::mutable_buffers_1 const& buffer) {
108 socket->async_read_some(buffer, handler);
111 template <typename stream_protocol>
112 bs::error_code BaseSocketMessenger<stream_protocol>::receive_msg(
113 ba::mutable_buffers_1 const& buffer) {
117 while (nread < ba::buffer_size(buffer)) {
119 boost::asio::read(*socket, ba::mutable_buffers_1{buffer + nread}, e);
121 if (e && e != ba::error::would_block) break;
127 template <typename stream_protocol>
128 size_t BaseSocketMessenger<stream_protocol>::available_bytes() {
129 boost::asio::socket_base::bytes_readable command{true};
130 socket->io_control(command);
131 return command.get();
134 template <typename stream_protocol>
135 unsigned short BaseSocketMessenger<stream_protocol>::local_port() const {
139 template <typename stream_protocol>
140 void BaseSocketMessenger<stream_protocol>::set_no_delay() {
141 const auto fd = socket->native_handle();
144 ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
145 reinterpret_cast<const char*>(&flag), sizeof(flag));
146 if (ret < 0) WARNING("Failed to disable TCP delay for socket");
149 template <typename stream_protocol>
150 void BaseSocketMessenger<stream_protocol>::close() {
154 template class BaseSocketMessenger<boost::asio::local::stream_protocol>;
155 template class BaseSocketMessenger<boost::asio::ip::tcp>;
156 } // namespace network