• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android-base/logging.h>
20 #include <android-base/strings.h>
21 
22 #include <algorithm>
23 
24 #include "host/commands/modem_simulator/modem_simulator.h"
25 
26 namespace cuttlefish {
27 
28 constexpr int32_t kMaxCommandLength = 4096;
29 
Client(cuttlefish::SharedFD fd)30 Client::Client(cuttlefish::SharedFD fd) : client_fd(fd) {}
31 
Client(cuttlefish::SharedFD fd,ClientType client_type)32 Client::Client(cuttlefish::SharedFD fd, ClientType client_type)
33     : type(client_type), client_fd(fd) {}
34 
operator ==(const Client & other) const35 bool Client::operator==(const Client& other) const {
36   return client_fd == other.client_fd;
37 }
38 
SendCommandResponse(std::string response) const39 void Client::SendCommandResponse(std::string response) const {
40   if (response.empty()) {
41     LOG(DEBUG) << "Invalid response, ignore!";
42     return;
43   }
44 
45   if (response.back() != '\r') {
46     response += '\r';
47   }
48   LOG(VERBOSE) << " AT< " << response;
49 
50   std::lock_guard<std::mutex> autolock(const_cast<Client*>(this)->write_mutex);
51   client_fd->Write(response.data(), response.size());
52 }
53 
SendCommandResponse(const std::vector<std::string> & responses) const54 void Client::SendCommandResponse(
55     const std::vector<std::string>& responses) const {
56   for (auto& response : responses) {
57     SendCommandResponse(response);
58   }
59 }
60 
ChannelMonitor(ModemSimulator * modem,cuttlefish::SharedFD server)61 ChannelMonitor::ChannelMonitor(ModemSimulator* modem,
62                                cuttlefish::SharedFD server)
63     : modem_(modem), server_(server) {
64   if (!cuttlefish::SharedFD::Pipe(&read_pipe_, &write_pipe_)) {
65     LOG(ERROR) << "Unable to create pipe, ignore";
66   }
67 
68   if (server_->IsOpen())
69     monitor_thread_ = std::thread([this]() { MonitorLoop(); });
70 }
71 
SetRemoteClient(cuttlefish::SharedFD client,bool is_accepted)72 void ChannelMonitor::SetRemoteClient(cuttlefish::SharedFD client, bool is_accepted) {
73   auto remote_client = std::make_unique<Client>(client, Client::REMOTE);
74 
75   if (is_accepted) {
76     // There may be new data from remote client before select.
77     remote_client->first_read_command_ = true;
78     ReadCommand(*remote_client);
79   }
80 
81   if (remote_client->client_fd->IsOpen()) {
82     remote_client->first_read_command_ = false;
83     remote_clients_.push_back(std::move(remote_client));
84     LOG(DEBUG) << "added one remote client";
85   }
86 
87   // Trigger monitor loop
88   if (write_pipe_->IsOpen()) {
89     write_pipe_->Write("OK", sizeof("OK"));
90   } else {
91     LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
92   }
93 }
94 
AcceptIncomingConnection()95 void ChannelMonitor::AcceptIncomingConnection() {
96   auto client_fd  = cuttlefish::SharedFD::Accept(*server_);
97   if (!client_fd->IsOpen()) {
98     LOG(ERROR) << "Error accepting connection on socket: " << client_fd->StrError();
99   } else {
100     auto client = std::make_unique<Client>(client_fd);
101     LOG(DEBUG) << "added one RIL client";
102     clients_.push_back(std::move(client));
103     if (clients_.size() == 1) {
104       // The first connected client default to be the unsolicited commands channel
105       modem_->OnFirstClientConnected();
106     }
107   }
108 }
109 
ReadCommand(Client & client)110 void ChannelMonitor::ReadCommand(Client& client) {
111   std::vector<char> buffer(kMaxCommandLength);
112   auto bytes_read = client.client_fd->Read(buffer.data(), buffer.size());
113   if (bytes_read <= 0) {
114     if (errno == EAGAIN && client.type == Client::REMOTE &&
115         client.first_read_command_) {
116       LOG(ERROR) << "After read 'REM' from remote client, and before select "
117           "no new data come.";
118       return;
119     }
120     LOG(DEBUG) << "Error reading from client fd: "
121                << client.client_fd->StrError();
122     client.client_fd->Close();  // Ignore errors here
123     // Erase client from the vector clients
124     auto& clients = client.type == Client::REMOTE ? remote_clients_ : clients_;
125     auto iter = std::find_if(
126         clients.begin(), clients.end(),
127         [&](std::unique_ptr<Client>& other) { return *other == client; });
128     if (iter != clients.end()) {
129       clients.erase(iter);
130     }
131     return;
132   }
133 
134   std::string& incomplete_command = client.incomplete_command;
135 
136   // Add the incomplete command from the last read
137   auto commands = std::string{incomplete_command.data()};
138   commands.append(buffer.data());
139 
140   incomplete_command.clear();
141 
142   // Replacing '\n' with '\r'
143   commands = android::base::StringReplace(commands, "\n", "\r", true);
144 
145   // Split into commands and dispatch
146   size_t pos = 0, r_pos = 0;  // '\r' or '\n'
147   while (r_pos != std::string::npos) {
148     if (modem_->IsWaitingSmsPdu()) {
149       r_pos = commands.find('\032', pos);  // In sms, find ctrl-z
150     } else {
151       r_pos = commands.find('\r', pos);
152     }
153     if (r_pos != std::string::npos) {
154       auto command = commands.substr(pos, r_pos - pos);
155       if (command.size() > 0) {  // "\r\r" ?
156         LOG(VERBOSE) << "AT> " << command;
157         modem_->DispatchCommand(client, command);
158       }
159       pos = r_pos + 1;  // Skip '\r'
160     } else if (pos < commands.length()) {  // Incomplete command
161       incomplete_command = commands.substr(pos);
162       LOG(DEBUG) << "incomplete command: " << incomplete_command;
163     }
164   }
165 }
166 
SendUnsolicitedCommand(std::string & response)167 void ChannelMonitor::SendUnsolicitedCommand(std::string& response) {
168   // The first accepted client default to be unsolicited command channel?
169   auto iter = clients_.begin();
170   if (iter != clients_.end()) {
171     iter->get()->SendCommandResponse(response);
172   } else {
173     LOG(DEBUG) << "No client connected yet.";
174   }
175 }
176 
SendRemoteCommand(cuttlefish::SharedFD client,std::string & response)177 void ChannelMonitor::SendRemoteCommand(cuttlefish::SharedFD client, std::string& response) {
178   auto iter = remote_clients_.begin();
179   for (; iter != remote_clients_.end(); ++iter) {
180     if (iter->get()->client_fd == client) {
181       iter->get()->SendCommandResponse(response);
182       return;
183     }
184   }
185   LOG(DEBUG) << "Remote client has closed.";
186 }
187 
CloseRemoteConnection(cuttlefish::SharedFD client)188 void ChannelMonitor::CloseRemoteConnection(cuttlefish::SharedFD client) {
189   auto iter = remote_clients_.begin();
190   for (; iter != remote_clients_.end(); ++iter) {
191     if (iter->get()->client_fd == client) {
192       iter->get()->client_fd->Close();
193       iter->get()->is_valid = false;
194 
195       // Trigger monitor loop
196       if (write_pipe_->IsOpen()) {
197         write_pipe_->Write("OK", sizeof("OK"));
198         LOG(DEBUG) << "asking to remove clients";
199       } else {
200         LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
201       }
202       return;
203     }
204   }
205   LOG(DEBUG) << "Remote client has been erased.";
206 }
207 
~ChannelMonitor()208 ChannelMonitor::~ChannelMonitor() {
209   if (write_pipe_->IsOpen()) {
210     write_pipe_->Write("KO", sizeof("KO"));
211   }
212 
213   if (monitor_thread_.joinable()) {
214     LOG(DEBUG) << "waiting for monitor thread to join";
215     monitor_thread_.join();
216   }
217 }
218 
removeInvalidClients(std::vector<std::unique_ptr<Client>> & clients)219 static void removeInvalidClients(std::vector<std::unique_ptr<Client>>& clients) {
220   auto iter = clients.begin();
221   for (; iter != clients.end();) {
222     if (iter->get()->is_valid) {
223       ++iter;
224     } else {
225       LOG(DEBUG) << "removed 1 client";
226       iter = clients.erase(iter);
227     }
228   }
229 }
230 
MonitorLoop()231 void ChannelMonitor::MonitorLoop() {
232   do {
233     cuttlefish::SharedFDSet read_set;
234     read_set.Set(server_);
235     read_set.Set(read_pipe_);
236     for (auto& client: clients_) {
237       if (client->is_valid) read_set.Set(client->client_fd);
238     }
239     for (auto& client: remote_clients_) {
240       if (client->is_valid) read_set.Set(client->client_fd);
241     }
242     int num_fds = cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
243     if (num_fds < 0) {
244       LOG(ERROR) << "Select call returned error : " << strerror(errno);
245       // std::exit(kSelectError);
246       break;
247     } else if (num_fds > 0) {
248       if (read_set.IsSet(server_)) {
249         AcceptIncomingConnection();
250       }
251       if (read_set.IsSet(read_pipe_)) {
252         std::string buf(2, ' ');
253         read_pipe_->Read(buf.data(), buf.size());  // Empty pipe
254         if (buf == std::string("KO")) {
255           LOG(DEBUG) << "requested to exit now";
256           break;
257         }
258         // clean the lists
259         removeInvalidClients(clients_);
260         removeInvalidClients(remote_clients_);
261       }
262       for (auto& client : clients_) {
263         if (read_set.IsSet(client->client_fd)) {
264           ReadCommand(*client);
265         }
266       }
267       for (auto& client : remote_clients_) {
268         if (read_set.IsSet(client->client_fd)) {
269           ReadCommand(*client);
270         }
271       }
272     } else {
273       // Ignore errors here
274       LOG(ERROR) << "Select call returned error : " << strerror(errno);
275     }
276   } while (true);
277 }
278 
279 }  // namespace cuttlefish
280