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