device/google/cuttlefish/host/commands/modem_simulator/sms_service.cpp

389 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "host/commands/modem_simulator/sms_service.h"
#include <android-base/logging.h>
#include "host/commands/modem_simulator/pdu_parser.h"
namespace cuttlefish {
SmsService::SmsService(int32_t service_id, ChannelMonitor* channel_monitor,
ThreadLooper* thread_looper)
: ModemService(service_id, this->InitializeCommandHandlers(),
channel_monitor, thread_looper) {
InitializeServiceState();
}
std::vector<CommandHandler> SmsService::InitializeCommandHandlers() {
std::vector<CommandHandler> command_handlers = {
CommandHandler("+CMGS",
[this](const Client& client, std::string& cmd) {
this->HandleSendSMS(client, cmd);
}),
CommandHandler("+CNMA",
[this](const Client& client, std::string& cmd) {
this->HandleSMSAcknowledge(client, cmd);
}),
CommandHandler("+CMGW",
[this](const Client& client, std::string& cmd) {
this->HandleWriteSMSToSim(client, cmd);
}),
CommandHandler("+CMGD",
[this](const Client& client, std::string& cmd) {
this->HandleDeleteSmsOnSim(client, cmd);
}),
CommandHandler("+CSCB",
[this](const Client& client, std::string& cmd) {
this->HandleBroadcastConfig(client, cmd);
}),
CommandHandler(
"+CSCA?",
[this](const Client& client) { this->HandleGetSmscAddress(client); }),
CommandHandler("+CSCA=",
[this](const Client& client, std::string& cmd) {
this->HandleSetSmscAddress(client, cmd);
}),
CommandHandler("+REMOTESMS",
[this](const Client& client, std::string& cmd) {
this->HandleReceiveRemoteSMS(client, cmd);
}),
};
return (command_handlers);
}
void SmsService::InitializeServiceState() {
is_waiting_sms_pdu_ = false;
is_waiting_sms_to_sim_ = false;
message_id_ = 1;
message_reference_ = 1;
broadcast_config_ = {0, "", ""};
}
void SmsService::SetupDependency(SimService* sim) { sim_service_ = sim; }
/**
* AT+CMGS
* This command sends message from a TE to the network (SMS-SUBMIT).
*
* Command Possible response(s)
* +CMGS=<length><CR> "> "
* PDU is given<ctrl-Z/ESC> +CMGS: <mr>[,<ackpdu>]<CR>OK
* +CMS ERROR: <err>
*
* <length>:must indicate the number of octets coded in the TP
* layer data unit to be given.
*
* see RIL_REQUEST_SEND_SMS in RIL
*/
void SmsService::HandleSendSMS(const Client& client, std::string& /*command*/) {
is_waiting_sms_pdu_ = true;
std::vector<std::string> responses;
responses.push_back("> ");
client.SendCommandResponse(responses);
}
/**
* AT+CNMA
* This command confirms reception of a new message (SMS-DELIVER or
* SMS-STATUS-REPORT) which is routed directly to the TE.
*
* Command Possible response(s)
* +CNMA [=<n>[, <length> [<CR> OK
* PDU is given<ctrl-Z/ESC>]]] +CMS ERROR: <err>
*
* <n>: integer type
* 0: command operates similarly as defined for the text mode
* 1: send RP-ACK
* 2: send RP-ERROR
* <length>: ACKPDU lengthoctet)
*
* see RIL_REQUEST_SMS_ACKNOWLEDGE in RIL
*/
void SmsService::HandleSMSAcknowledge(const Client& client, std::string& /*command*/) {
client.SendCommandResponse("OK");
}
/*
* AT+CMGW
* This command stores message (either SMS-DELIVER or SMS-SUBMIT)
* to memory storage <mem2>.
*
* Command Possible response(s)
* +CMGW=<length>[,<stat>]<CR> "> "
* PDU is given <ctrl-Z/ESC> +CMGW: <index>
* +CMS ERROR: <err>
* <length>: the length of TPDU(bit) with a range of 9-160
* < stat >: integer:
* 0: Unread Message. (MT)
* 1: Read Message. (MT)
* 2: Unsent Message. (MO)
* 3: Sent Message. (MO)
* < index>: index id of <mem2>
*
* see RIL_REQUEST_WRITE_SMS_TO_SIM in RIL
*/
void SmsService::HandleWriteSMSToSim(const Client& client, std::string& command) {
is_waiting_sms_to_sim_ = true;
CommandParser cmd(command);
cmd.SkipPrefix(); // skip "AT+CMGW="
cmd.SkipComma();
sms_status_on_sim_ = (SmsMessage::SmsStatus)cmd.GetNextInt();
client.SendCommandResponse("> ");
}
/**
* AT+CMGD
* This command deletes message from preferred message storage <mem1>
* location <index>.
*
* Command Possible response(s)
* +CMGD=<index>[, <DelFlag>] OK
* +CMS ERROR: <err>
* < index>: index id of <mem2>
*
* see RIL_REQUEST_DELETE_SMS_ON_SIM in RIL
*/
void SmsService::HandleDeleteSmsOnSim(const Client& client, std::string& command) {
CommandParser cmd(command);
cmd.SkipPrefix(); // skip "AT+CMGD="
int index = cmd.GetNextInt();
auto iter = messages_on_sim_card_.find(index);
if (iter == messages_on_sim_card_.end()) {
client.SendCommandResponse(kCmeErrorInvalidIndex); // No such message
return;
}
messages_on_sim_card_.erase(iter);
client.SendCommandResponse("OK");
}
/**
* AT+CSCB
* Set command selects which types of CBMs are to be received by the ME.
*
* Command Possible response(s)
* +CSCB=[<mode>[,<mids>[,<dcss>]]] OK
* +CSCB? +CSCB: <mode>,<mids>,<dcss>
*
* <mode>:
* 0: message types specified in <mids> and <dcss> are accepted
* 1: message types specified in <mids> and <dcss> are not accepted
* <mids>: string type; all different possible combinations of CBM message
* identifiers (refer <mid>).
* <dcss>: string type; all different possible combinations of CBM data coding
* schemes.
*
* see RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG &
* RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG in RIL
* Notes: This command is allowed in TEXT mode.
*/
void SmsService::HandleBroadcastConfig(const Client& client, std::string& command) {
std::vector<std::string> responses;
CommandParser cmd(command);
cmd.SkipPrefix();
if (*cmd == "AT+CSCB?") { // Query
std::stringstream ss;
ss << "+CSCB: " << broadcast_config_.mode << ","
<< broadcast_config_.mids << ","
<< broadcast_config_.dcss;
responses.push_back(ss.str());
} else { // Set
broadcast_config_.mode = cmd.GetNextInt();
broadcast_config_.mids = cmd.GetNextStr();
broadcast_config_.dcss = cmd.GetNextStr();
}
responses.push_back("OK");
client.SendCommandResponse(responses);
}
/**
* AT+CSCA
* Set command updates the SMSC address, through which mobile originated
* SMs are transmitted.
*
* Command Possible response(s)
* +CSCA=<sca>[,<tosca>] OK
* +CSCA? +CSCA: <sca>,<tosca>
*
* <sca>: service center address, its maximum length is 20.
* <tosca>: service center address format,protocol uses 8-bit address integer.
*
* see RIL_REQUEST_SET_SMSC_ADDRESS in RIL
*/
void SmsService::HandleGetSmscAddress(const Client& client) {
std::vector<std::string> responses;
std::stringstream ss;
ss << "+CSCA: " << sms_service_center_address_.sca << ","
<< sms_service_center_address_.tosca;
responses.push_back(ss.str());
responses.push_back("OK");
client.SendCommandResponse(responses);
}
void SmsService::HandleSetSmscAddress(const Client& client, std::string& command) {
CommandParser cmd(command);
cmd.SkipPrefix(); // skip "AT+CSCA="
sms_service_center_address_.sca = cmd.GetNextStr();
sms_service_center_address_.tosca = cmd.GetNextInt();
client.SendCommandResponse("OK");
}
void SmsService::SendSmsToRemote(std::string remote_port, PDUParser& sms_pdu) {
auto remote_client = ConnectToRemoteCvd(remote_port);
if (!remote_client->IsOpen()) {
return;
}
auto local_host_id = GetHostId();
auto pdu = sms_pdu.CreateRemotePDU(local_host_id);
std::string command = "AT+REMOTESMS=" + pdu + "\r";
std::string token = "REM0";
remote_client->Write(token.data(), token.size());
remote_client->Write(command.data(), command.size());
}
/* process AT+CMGS PDU */
void SmsService::HandleSendSMSPDU(const Client& client, std::string& command) {
is_waiting_sms_pdu_ = false;
std::vector<std::string> responses;
PDUParser sms_pdu(command);
if (!sms_pdu.IsValidPDU()) {
/* Invalid PDU mode parameter */
client.SendCommandResponse(kCmsErrorInvalidPDUModeParam);
return;
}
std::string phone_number = sms_pdu.GetPhoneNumberFromAddress();
int port = 0;
if (phone_number.length() == 11) {
port = std::stoi(phone_number.substr(7));
} else if (phone_number.length() == 4) {
port = std::stoi(phone_number);
}
if (phone_number == "") { /* Phone number unknown */
LOG(ERROR) << "Failed to get phone number form address";
client.SendCommandResponse(kCmsErrorSCAddressUnknown);
return;
} else if (port >= kRemotePortRange.first &&
port <= kRemotePortRange.second) {
auto remote_host_port = std::to_string(port);
if (GetHostId() == remote_host_port) { // Send SMS to local host port
thread_looper_->Post(
makeSafeCallback<SmsService>(
this,
[&sms_pdu](SmsService* me) { me->HandleReceiveSMS(sms_pdu); }),
std::chrono::seconds(1));
} else { // Send SMS to remote host port
SendSmsToRemote(remote_host_port, sms_pdu);
}
} else if (sim_service_ && phone_number == sim_service_->GetPhoneNumber()) {
/* Local phone number */
thread_looper_->Post(
makeSafeCallback<SmsService>(
this, [sms_pdu](SmsService* me) { me->HandleReceiveSMS(sms_pdu); }),
std::chrono::seconds(1));
} /* else pretend send SMS success */
std::stringstream ss;
ss << "+CMGS: " << ++message_reference_;
responses.push_back(ss.str());
responses.push_back("OK");
client.SendCommandResponse(responses);
if (sms_pdu.IsNeededStatuReport()) {
int ref = message_reference_;
thread_looper_->Post(
makeSafeCallback<SmsService>(this,
[sms_pdu, ref](SmsService* me) {
me->HandleSMSStatuReport(sms_pdu, ref);
}),
std::chrono::seconds(1));
}
}
/* AT+CMGS callback function */
void SmsService::HandleReceiveSMS(PDUParser sms_pdu) {
std::string pdu = sms_pdu.CreatePDU();
if (pdu != "") {
SendUnsolicitedCommand("+CMT: 0");
SendUnsolicitedCommand(pdu);
}
}
/* Process AT+CMGW PDU */
void SmsService::HandleWriteSMSPduToSim(const Client& client, std::string& command) {
is_waiting_sms_to_sim_ = false;
SmsMessage message;
message.status = sms_status_on_sim_;
message.message = command;
int index = message_id_++;
messages_on_sim_card_[index] = message;
std::vector<std::string> responses;
std::stringstream ss;
ss << "+CMGW: " << index;
responses.push_back(ss.str());
responses.push_back("OK");
client.SendCommandResponse(responses);
}
/* SMS Status Report */
void SmsService::HandleSMSStatuReport(PDUParser sms_pdu, int message_reference) {
std::string response;
std::stringstream ss;
auto pdu = sms_pdu.CreateStatuReport(message_reference);
auto pdu_length = (pdu.size() - 2) / 2; // Not Including SMSC Address
if (pdu != "" && pdu_length > 0) {
ss << "+CDS: " << pdu_length;
SendUnsolicitedCommand(ss.str());
SendUnsolicitedCommand(pdu);
}
}
/* AT+REMOTESMS=PDU */
void SmsService::HandleReceiveRemoteSMS(const Client& /*client*/, std::string& command) {
CommandParser cmd(command);
cmd.SkipPrefix();
std::string pdu(*cmd);
PDUParser sms_pdu(pdu);
if (!sms_pdu.IsValidPDU()) {
LOG(ERROR) << "Failed to decode PDU";
return;
}
pdu = sms_pdu.CreatePDU();
if (pdu != "") {
SendUnsolicitedCommand("+CMT: 0");
SendUnsolicitedCommand(pdu);
}
}
} // namespace cuttlefish