// // Copyright (C) 2021 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 "common/libs/confui/packet.h" #include #include #include #include #include "common/libs/confui/protocol.h" #include "common/libs/confui/utils.h" #include "common/libs/fs/shared_buf.h" namespace cuttlefish { namespace confui { namespace packet { ConfUiMessage PayloadToConfUiMessage(const std::string& str_to_parse) { auto tokens = android::base::Split(str_to_parse, ":"); ConfUiCheck(tokens.size() >= 3) << "PayloadToConfUiMessage takes \"" + str_to_parse + "\"" << "and does not have 3 tokens"; std::string msg; std::for_each(tokens.begin() + 2, tokens.end() - 1, [&msg](auto& token) { msg.append(token + ":"); }); msg.append(*tokens.rbegin()); return {tokens[0], tokens[1], msg}; } // Use only this function to make a packet to send over the confirmation // ui packet layer template static Payload ToPayload(const ConfUiCmd cmd, const std::string& session_id, Args&&... args) { std::string cmd_str = ToString(cmd); std::string msg = ArgsToString(session_id, ":", cmd_str, ":", std::forward(args)...); PayloadHeader header; header.payload_length_ = msg.size(); return {header, msg}; } template static bool WritePayload(SharedFD d, const ConfUiCmd cmd, const std::string& session_id, Args&&... args) { if (!d->IsOpen()) { LOG(ERROR) << "file, socket, etc, is not open to write"; return false; } auto [payload, msg] = ToPayload(cmd, session_id, std::forward(args)...); auto nwrite = WriteAll(d, reinterpret_cast(&payload), sizeof(payload)); if (nwrite != sizeof(payload)) { return false; } nwrite = cuttlefish::WriteAll(d, msg.c_str(), msg.size()); if (nwrite != msg.size()) { return false; } return true; } static std::optional ReadPayload(SharedFD s) { if (!s->IsOpen()) { LOG(ERROR) << "file, socket, etc, is not open to read"; return std::nullopt; } PayloadHeader p; auto nread = ReadExactBinary(s, &p); if (nread != sizeof(p)) { return std::nullopt; } if (p.payload_length_ == 0) { return {{SESSION_ANY, ToString(ConfUiCmd::kUnknown), std::string{""}}}; } if (p.payload_length_ >= kMaxPayloadLength) { LOG(ERROR) << "Payload length must be less than " << kMaxPayloadLength; return std::nullopt; } std::unique_ptr buf{new char[p.payload_length_ + 1]}; nread = ReadExact(s, buf.get(), p.payload_length_); buf[p.payload_length_] = 0; if (nread != p.payload_length_) { return std::nullopt; } std::string msg_to_parse{buf.get()}; auto [session_id, type, contents] = PayloadToConfUiMessage(msg_to_parse); return {{session_id, type, contents}}; } std::optional RecvConfUiMsg(SharedFD fd) { return ReadPayload(fd); } bool SendCmd(SharedFD fd, const std::string& session_id, ConfUiCmd cmd, const std::string& additional_info) { return WritePayload(fd, cmd, session_id, additional_info); } bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success, const std::string& additional_info) { return WritePayload(fd, ConfUiCmd::kCliAck, session_id, ToCliAckMessage(is_success, additional_info)); } bool SendResponse(SharedFD fd, const std::string& session_id, const std::string& additional_info) { return WritePayload(fd, ConfUiCmd::kCliRespond, session_id, additional_info); } } // end of namespace packet } // end of namespace confui } // end of namespace cuttlefish