23efc7871755e2d1371ad885fd01333c88d0243b
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / network / base_socket_messenger.cpp
1 /*
2  * Copyright © 2013-2014 Canonical Ltd.
3  *
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.
7  *
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.
12  *
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/>.
15  *
16  * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17  */
18
19 #include "anbox/network/base_socket_messenger.h"
20 #include "anbox/common/variable_length_array.h"
21 #include "anbox/logger.h"
22
23 #include <boost/throw_exception.hpp>
24
25 #include <errno.h>
26 #include <string.h>
27
28 #include <stdexcept>
29
30 namespace bs = boost::system;
31 namespace ba = boost::asio;
32
33 namespace {
34 /// Buffers need to be big enough to support messages
35 unsigned int const serialization_buffer_size = 2048;
36 }
37
38 namespace anbox {
39 namespace network {
40 template <typename stream_protocol>
41 BaseSocketMessenger<stream_protocol>::BaseSocketMessenger() {}
42
43 template <typename stream_protocol>
44 BaseSocketMessenger<stream_protocol>::BaseSocketMessenger(
45     std::shared_ptr<ba::basic_stream_socket<stream_protocol>> const& socket) {
46   setup(socket);
47 }
48
49 template <typename stream_protocol>
50 BaseSocketMessenger<stream_protocol>::~BaseSocketMessenger() {}
51
52 template <typename stream_protocol>
53 void BaseSocketMessenger<stream_protocol>::setup(
54     std::shared_ptr<ba::basic_stream_socket<stream_protocol>> const& s) {
55   socket = 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);
60 }
61
62 template <typename stream_protocol>
63 Credentials BaseSocketMessenger<stream_protocol>::creds() const {
64   struct ucred cr;
65   socklen_t cl = sizeof(cr);
66
67   auto status = getsockopt(socket_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl);
68
69   if (status)
70     BOOST_THROW_EXCEPTION(
71         std::runtime_error("Failed to query client socket credentials"));
72
73   return {cr.pid, cr.uid, cr.gid};
74 }
75
76 template <typename stream_protocol>
77 ssize_t BaseSocketMessenger<stream_protocol>::send_raw(char const* data,
78                                                        size_t length) {
79   VariableLengthArray<serialization_buffer_size> whole_message{length};
80   std::copy(data, data + length, whole_message.data());
81
82   std::unique_lock<std::mutex> lg(message_lock);
83   return ::send(socket_fd, data, length, MSG_NOSIGNAL);
84 }
85
86 template <typename stream_protocol>
87 void BaseSocketMessenger<stream_protocol>::send(char const* data,
88                                                 size_t length) {
89   VariableLengthArray<serialization_buffer_size> whole_message{length};
90   std::copy(data, data + length, whole_message.data());
91
92   for (;;) {
93     try {
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;
99       throw;
100     }
101     break;
102   }
103 }
104
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);
109 }
110
111 template <typename stream_protocol>
112 bs::error_code BaseSocketMessenger<stream_protocol>::receive_msg(
113     ba::mutable_buffers_1 const& buffer) {
114   bs::error_code e;
115   size_t nread = 0;
116
117   while (nread < ba::buffer_size(buffer)) {
118     nread +=
119         boost::asio::read(*socket, ba::mutable_buffers_1{buffer + nread}, e);
120
121     if (e && e != ba::error::would_block) break;
122   }
123
124   return e;
125 }
126
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();
132 }
133
134 template <typename stream_protocol>
135 unsigned short BaseSocketMessenger<stream_protocol>::local_port() const {
136   return 0;
137 }
138
139 template <typename stream_protocol>
140 void BaseSocketMessenger<stream_protocol>::set_no_delay() {
141   const auto fd = socket->native_handle();
142   int flag = 1;
143   const auto ret =
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");
147 }
148
149 template <typename stream_protocol>
150 void BaseSocketMessenger<stream_protocol>::close() {
151   socket->close();
152 }
153
154 template class BaseSocketMessenger<boost::asio::local::stream_protocol>;
155 template class BaseSocketMessenger<boost::asio::ip::tcp>;
156 }  // namespace network
157 }  // namespace anbox