blob: d5be03a161e47b116e2aead02da495e5ba6e1e42 [file] [log] [blame]
//
// 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 <algorithm>
#include <iostream>
#include <android-base/logging.h>
#include <android-base/strings.h>
#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 <typename... Args>
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>(args)...);
PayloadHeader header;
header.payload_length_ = msg.size();
return {header, msg};
}
template <typename... Args>
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>(args)...);
auto nwrite =
WriteAll(d, reinterpret_cast<const char*>(&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<ConfUiMessage> 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<char[]> 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<ConfUiMessage> 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