24d3bb7577f94a173d7e399a224c0fe027d0f80b
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / qemu / adb_message_processor.cpp
1 /*
2  * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 3, as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranties of
10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11  * PURPOSE.  See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 #include "anbox/qemu/adb_message_processor.h"
19 #include "anbox/network/delegate_connection_creator.h"
20 #include "anbox/network/delegate_message_processor.h"
21 #include "anbox/network/tcp_socket_messenger.h"
22 #include "anbox/utils.h"
23
24 #include <fstream>
25 #include <functional>
26
27 namespace {
28 const unsigned short default_adb_client_port{5037};
29 // For the listening port we have to use an odd port in the 5555-5585 range so
30 // the host can find us on start. See
31 // https://developer.android.com/studio/command-line/adb.html.
32 const unsigned short default_host_listen_port{5559};
33 constexpr const char *loopback_address{"127.0.0.1"};
34 const std::string accept_command{"accept"};
35 const std::string ok_command{"ok"};
36 const std::string ko_command{"ko"};
37 const std::string start_command{"start"};
38 // This timeount should be too high to not cause a too long wait time for the
39 // user until we connect to the adb host instance after it appeared and not
40 // too short to not put unnecessary burden on the CPU.
41 const boost::posix_time::seconds default_adb_wait_time{1};
42 }
43
44 using namespace std::placeholders;
45
46 namespace anbox {
47 namespace qemu {
48 std::mutex AdbMessageProcessor::active_instance_{};
49
50 AdbMessageProcessor::AdbMessageProcessor(
51     const std::shared_ptr<Runtime> &rt,
52     const std::shared_ptr<network::SocketMessenger> &messenger)
53     : runtime_(rt),
54       state_(waiting_for_guest_accept_command),
55       expected_command_(accept_command),
56       messenger_(messenger),
57       lock_(active_instance_, std::defer_lock) {
58 }
59
60 AdbMessageProcessor::~AdbMessageProcessor() {
61   state_ = closed_by_host;
62
63   host_connector_.reset();
64 }
65
66 void AdbMessageProcessor::advance_state() {
67   switch (state_) {
68     case waiting_for_guest_accept_command:
69       // Try to get a lock here as if we already have another processor
70       // running we don't have to do anything here until that one is done.
71       // The container directly starts a second connection once the first
72       // one is established but will not use it until the active one is closed.
73       lock_.lock();
74
75       if (state_ == closed_by_host) {
76         host_connector_.reset();
77         return;
78       }
79
80       wait_for_host_connection();
81       break;
82     case waiting_for_host_connection:
83       messenger_->send(reinterpret_cast<const char *>(ok_command.data()),
84                        ok_command.size());
85       state_ = waiting_for_guest_start_command;
86       expected_command_ = start_command;
87       break;
88     case waiting_for_guest_start_command:
89       state_ = proxying_data;
90       read_next_host_message();
91       break;
92     case proxying_data:
93       break;
94     case closed_by_host:
95       // Close the connection to the container as our adb host connection
96       // turned down. The container will try to establish a connection
97       // immediately again and we will handle that by waiting for the
98       // host adb to run up again.
99       messenger_->close();
100       break;
101     case closed_by_container:
102       // In this case the container will close the pipe connection and this
103       // message processor will be deleted once the owning socket connection
104       // is closed.
105       break;
106     default:
107       break;
108   }
109 }
110
111 void AdbMessageProcessor::wait_for_host_connection() {
112   if (state_ != waiting_for_guest_accept_command)
113     return;
114
115   if (!host_connector_) {
116     host_connector_ = std::make_shared<network::TcpSocketConnector>(
117         boost::asio::ip::address_v4::from_string(loopback_address),
118         default_host_listen_port, runtime_,
119         std::make_shared<
120             network::DelegateConnectionCreator<boost::asio::ip::tcp>>(
121             std::bind(&AdbMessageProcessor::on_host_connection, this, _1)));
122   }
123
124   try {
125     // Notify the adb host instance so that it knows on which port our
126     // proxy is waiting for incoming connections.
127     auto messenger = std::make_shared<network::TcpSocketMessenger>(
128         boost::asio::ip::address_v4::from_string(loopback_address), default_adb_client_port, runtime_);
129     auto message = utils::string_format("host:emulator:%d", default_host_listen_port);
130     auto handshake = utils::string_format("%04x%s", message.size(), message.c_str());
131     messenger->send(handshake.data(), handshake.size());
132   } catch (...) {
133     // Server not up. No problem, it will contact us when started.
134   }
135 }
136
137 void AdbMessageProcessor::on_host_connection(std::shared_ptr<boost::asio::basic_stream_socket<boost::asio::ip::tcp>> const &socket) {
138   host_messenger_ = std::make_shared<network::TcpSocketMessenger>(socket);
139
140   // set_no_delay() reduces the latency of sending data, at the cost
141   // of creating more TCP packets on the connection. It's useful when
142   // doing lots of small send() calls, like the ADB protocol requires.
143   // And since this is on localhost, the packet increase should not be
144   // noticeable.
145   host_messenger_->set_no_delay();
146
147   // Let adb inside the container know that we have a connection to
148   // the adb host instance
149   messenger_->send(reinterpret_cast<const char *>(ok_command.data()), ok_command.size());
150
151   state_ = waiting_for_guest_start_command;
152   expected_command_ = start_command;
153 }
154
155 void AdbMessageProcessor::read_next_host_message() {
156   auto callback = std::bind(&AdbMessageProcessor::on_host_read_size, this, _1, _2);
157   host_messenger_->async_receive_msg(callback, boost::asio::buffer(host_buffer_));
158 }
159
160 void AdbMessageProcessor::on_host_read_size(const boost::system::error_code &error, std::size_t bytes_read) {
161   if (error) {
162     // When AdbMessageProcessor is destroyed on program termination, the sockets
163     // are closed and the standing operations are canceled. But, the callback is
164     // still called even in that case, and the object has already been
165     // deleted. We detect that condition by looking at the error code and avoid
166     // touching *this in that case.
167     if (error == boost::system::errc::operation_canceled)
168       return;
169
170     // For other errors, we assume the connection with the host is dropped. We
171     // close the connection to the container's adbd, which will trigger the
172     // deletion of this AdbMessageProcessor instance and free resources (most
173     // importantly, default_host_listen_port and the lock). The standing
174     // connection that adbd opened can then proceed and wait for the host to be
175     // up again.
176     state_ = closed_by_host;
177     messenger_->close();
178     return;
179   }
180
181   messenger_->send(reinterpret_cast<const char *>(host_buffer_.data()), bytes_read);
182   read_next_host_message();
183 }
184
185 bool AdbMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
186   if (state_ == proxying_data) {
187     host_messenger_->send(reinterpret_cast<const char *>(data.data()),
188                           data.size());
189     return true;
190   }
191
192   for (const auto &byte : data) buffer_.push_back(byte);
193
194   if (expected_command_.size() > 0 &&
195       buffer_.size() >= expected_command_.size()) {
196     if (::memcmp(buffer_.data(), expected_command_.data(), data.size()) != 0) {
197       // We got not the command we expected and will terminate here
198       return false;
199     }
200
201     buffer_.erase(buffer_.begin(), buffer_.begin() + expected_command_.size());
202     expected_command_.clear();
203
204     advance_state();
205   }
206
207   return true;
208 }
209 }  // namespace qemu
210 }  // namespace anbox