1
2 //
3 // Copyright (C) 2020 The Android Open Source Project
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 #include "host/commands/modem_simulator/channel_monitor.h"
18
19 #include <algorithm>
20
21 #include <android-base/logging.h>
22 #include <android-base/strings.h>
23
24 #include "common/libs/fs/shared_buf.h"
25 #include "common/libs/fs/shared_select.h"
26 #include "host/commands/modem_simulator/modem_simulator.h"
27
28 namespace cuttlefish {
29
30 constexpr int32_t kMaxCommandLength = 4096;
31
32 size_t ClientId::next_id_ = 0;
33
ClientId()34 ClientId::ClientId() {
35 id_ = next_id_;
36 next_id_++;
37 }
38
operator ==(const ClientId & other) const39 bool ClientId::operator==(const ClientId& other) const {
40 return id_ == other.id_;
41 }
42
Client(SharedFD fd)43 Client::Client(SharedFD fd) : client_read_fd_(fd), client_write_fd_(fd) {}
44
Client(SharedFD read,SharedFD write)45 Client::Client(SharedFD read, SharedFD write)
46 : client_read_fd_(std::move(read)), client_write_fd_(std::move(write)) {}
47
Client(SharedFD fd,ClientType client_type)48 Client::Client(SharedFD fd, ClientType client_type)
49 : type(client_type), client_read_fd_(fd), client_write_fd_(fd) {}
50
Client(SharedFD read,SharedFD write,ClientType client_type)51 Client::Client(SharedFD read, SharedFD write, ClientType client_type)
52 : type(client_type),
53 client_read_fd_(std::move(read)),
54 client_write_fd_(std::move(write)) {}
55
operator ==(const Client & other) const56 bool Client::operator==(const Client& other) const {
57 return client_read_fd_ == other.client_read_fd_ &&
58 client_write_fd_ == other.client_write_fd_;
59 }
60
SendCommandResponse(std::string response) const61 void Client::SendCommandResponse(std::string response) const {
62 if (response.empty()) {
63 LOG(DEBUG) << "Invalid response, ignore!";
64 return;
65 }
66
67 if (response.back() != '\r') {
68 response += '\r';
69 }
70 LOG(VERBOSE) << " AT< " << response;
71
72 std::lock_guard<std::mutex> lock(write_mutex);
73 WriteAll(client_write_fd_, response);
74 }
75
SendCommandResponse(const std::vector<std::string> & responses) const76 void Client::SendCommandResponse(
77 const std::vector<std::string>& responses) const {
78 for (auto& response : responses) {
79 SendCommandResponse(response);
80 }
81 }
82
ChannelMonitor(ModemSimulator & modem,SharedFD server)83 ChannelMonitor::ChannelMonitor(ModemSimulator& modem, SharedFD server)
84 : modem_(modem), server_(std::move(server)) {
85 if (!SharedFD::Pipe(&read_pipe_, &write_pipe_)) {
86 LOG(ERROR) << "Unable to create pipe, ignore";
87 }
88
89 if (server_->IsOpen()) {
90 monitor_thread_ = std::thread([this]() { MonitorLoop(); });
91 }
92 }
93
SetRemoteClient(SharedFD client,bool is_accepted)94 ClientId ChannelMonitor::SetRemoteClient(SharedFD client, bool is_accepted) {
95 auto remote_client = std::make_unique<Client>(client, Client::REMOTE);
96 auto id = remote_client->Id();
97
98 if (is_accepted) {
99 // There may be new data from remote client before select.
100 remote_client->first_read_command_ = true;
101 ReadCommand(*remote_client);
102 }
103
104 if (remote_client->client_read_fd_->IsOpen() &&
105 remote_client->client_write_fd_->IsOpen()) {
106 remote_client->first_read_command_ = false;
107 remote_clients_.push_back(std::move(remote_client));
108 LOG(DEBUG) << "added one remote client";
109 }
110
111 // Trigger monitor loop
112 if (write_pipe_->IsOpen()) {
113 write_pipe_->Write("OK", sizeof("OK"));
114 } else {
115 LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
116 }
117 return id;
118 }
119
AcceptIncomingConnection()120 void ChannelMonitor::AcceptIncomingConnection() {
121 auto client_fd = SharedFD::Accept(*server_);
122 if (!client_fd->IsOpen()) {
123 LOG(ERROR) << "Error accepting connection on socket: " << client_fd->StrError();
124 } else {
125 auto client = std::make_unique<Client>(client_fd);
126 LOG(DEBUG) << "added one RIL client";
127 clients_.push_back(std::move(client));
128 if (clients_.size() == 1) {
129 // The first connected client default to be the unsolicited commands channel
130 modem_.OnFirstClientConnected();
131 }
132 }
133 }
134
ReadCommand(Client & client)135 void ChannelMonitor::ReadCommand(Client& client) {
136 std::vector<char> buffer(kMaxCommandLength);
137 auto bytes_read = client.client_read_fd_->Read(buffer.data(), buffer.size());
138 if (bytes_read <= 0) {
139 if (errno == EAGAIN && client.type == Client::REMOTE &&
140 client.first_read_command_) {
141 LOG(ERROR) << "After read 'REM' from remote client, and before select "
142 "no new data come.";
143 return;
144 }
145 LOG(DEBUG) << "Error reading from client fd: "
146 << client.client_read_fd_->StrError();
147 client.client_read_fd_->Close(); // Ignore errors here
148 client.client_write_fd_->Close();
149 // Erase client from the vector clients
150 auto& clients = client.type == Client::REMOTE ? remote_clients_ : clients_;
151 auto iter = std::find_if(
152 clients.begin(), clients.end(),
153 [&](std::unique_ptr<Client>& other) { return *other == client; });
154 if (iter != clients.end()) {
155 clients.erase(iter);
156 }
157 return;
158 }
159
160 std::string& incomplete_command = client.incomplete_command;
161
162 // Add the incomplete command from the last read
163 auto commands = std::string{incomplete_command.data()};
164 commands.append(buffer.data());
165
166 incomplete_command.clear();
167
168 // Replacing '\n' with '\r'
169 commands = android::base::StringReplace(commands, "\n", "\r", true);
170
171 // Split into commands and dispatch
172 size_t pos = 0, r_pos = 0; // '\r' or '\n'
173 while (r_pos != std::string::npos) {
174 if (modem_.IsWaitingSmsPdu()) {
175 r_pos = commands.find('\032', pos); // In sms, find ctrl-z
176 } else {
177 r_pos = commands.find('\r', pos);
178 }
179 if (r_pos != std::string::npos) {
180 auto command = commands.substr(pos, r_pos - pos);
181 if (command.size() > 0) { // "\r\r" ?
182 LOG(VERBOSE) << "AT> " << command;
183 modem_.DispatchCommand(client, command);
184 }
185 pos = r_pos + 1; // Skip '\r'
186 } else if (pos < commands.length()) { // Incomplete command
187 incomplete_command = commands.substr(pos);
188 LOG(VERBOSE) << "incomplete command: " << incomplete_command;
189 }
190 }
191 }
192
SendUnsolicitedCommand(std::string & response)193 void ChannelMonitor::SendUnsolicitedCommand(std::string& response) {
194 // The first accepted client default to be unsolicited command channel?
195 auto iter = clients_.begin();
196 if (iter != clients_.end()) {
197 iter->get()->SendCommandResponse(response);
198 } else {
199 LOG(DEBUG) << "No client connected yet.";
200 }
201 }
202
SendRemoteCommand(ClientId client,std::string & response)203 void ChannelMonitor::SendRemoteCommand(ClientId client, std::string& response) {
204 auto iter = remote_clients_.begin();
205 for (; iter != remote_clients_.end(); ++iter) {
206 if (iter->get()->Id() == client) {
207 iter->get()->SendCommandResponse(response);
208 return;
209 }
210 }
211 LOG(DEBUG) << "Remote client has closed.";
212 }
213
CloseRemoteConnection(ClientId client)214 void ChannelMonitor::CloseRemoteConnection(ClientId client) {
215 auto iter = remote_clients_.begin();
216 for (; iter != remote_clients_.end(); ++iter) {
217 if (iter->get()->Id() == client) {
218 iter->get()->client_read_fd_->Close();
219 iter->get()->client_write_fd_->Close();
220 iter->get()->is_valid = false;
221
222 // Trigger monitor loop
223 if (write_pipe_->IsOpen()) {
224 write_pipe_->Write("OK", sizeof("OK"));
225 LOG(DEBUG) << "asking to remove clients";
226 } else {
227 LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
228 }
229 return;
230 }
231 }
232 LOG(DEBUG) << "Remote client has been erased.";
233 }
234
~ChannelMonitor()235 ChannelMonitor::~ChannelMonitor() {
236 if (write_pipe_->IsOpen()) {
237 write_pipe_->Write("KO", sizeof("KO"));
238 }
239
240 if (monitor_thread_.joinable()) {
241 LOG(DEBUG) << "waiting for monitor thread to join";
242 monitor_thread_.join();
243 }
244 }
245
removeInvalidClients(std::vector<std::unique_ptr<Client>> & clients)246 void ChannelMonitor::removeInvalidClients(
247 std::vector<std::unique_ptr<Client>>& clients) {
248 auto iter = clients.begin();
249 for (; iter != clients.end();) {
250 if (iter->get()->is_valid) {
251 ++iter;
252 } else {
253 LOG(DEBUG) << "removed 1 client";
254 iter = clients.erase(iter);
255 }
256 }
257 }
258
MonitorLoop()259 void ChannelMonitor::MonitorLoop() {
260 do {
261 cuttlefish::SharedFDSet read_set;
262 read_set.Set(server_);
263 read_set.Set(read_pipe_);
264 for (auto& client : clients_) {
265 if (client->is_valid) {
266 read_set.Set(client->client_read_fd_);
267 }
268 }
269 for (auto& client : remote_clients_) {
270 if (client->is_valid) {
271 read_set.Set(client->client_read_fd_);
272 }
273 }
274 int num_fds = cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
275 if (num_fds < 0) {
276 LOG(ERROR) << "Select call returned error : " << strerror(errno);
277 // std::exit(kSelectError);
278 break;
279 } else if (num_fds > 0) {
280 if (read_set.IsSet(server_)) {
281 AcceptIncomingConnection();
282 }
283 if (read_set.IsSet(read_pipe_)) {
284 std::string buf(2, ' ');
285 read_pipe_->Read(buf.data(), buf.size()); // Empty pipe
286 if (buf == std::string("KO")) {
287 LOG(DEBUG) << "requested to exit now";
288 break;
289 }
290 // clean the lists
291 removeInvalidClients(clients_);
292 removeInvalidClients(remote_clients_);
293 }
294 for (auto& client : clients_) {
295 if (read_set.IsSet(client->client_read_fd_)) {
296 ReadCommand(*client);
297 }
298 }
299 for (auto& client : remote_clients_) {
300 if (read_set.IsSet(client->client_read_fd_)) {
301 ReadCommand(*client);
302 }
303 }
304 } else {
305 // Ignore errors here
306 LOG(ERROR) << "Select call returned error : " << strerror(errno);
307 }
308 } while (true);
309 }
310
311 } // namespace cuttlefish
312