138 lines
4.3 KiB
C++
138 lines
4.3 KiB
C++
//
|
|
// 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.
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include <android-base/logging.h>
|
|
#include <android-base/strings.h>
|
|
|
|
#include "common/libs/confui/packet_types.h"
|
|
#include "common/libs/confui/utils.h"
|
|
#include "common/libs/fs/shared_buf.h"
|
|
#include "common/libs/fs/shared_fd.h"
|
|
|
|
/**
|
|
* @file packet.h
|
|
*
|
|
* @brief lowest-level packet for communication between host & guest
|
|
*
|
|
* Each packet has three fields
|
|
* 1. session_id_: the name of the currently active confirmation UI session
|
|
* 2. type_: the type of command/response. E.g. start, stop, ack, abort, etc
|
|
* 3. additional_info_: all the other additional information
|
|
*
|
|
* The binary represenation of each packet is as follows:
|
|
* n:L[1]:L[2]:...:L[n]:data[1]data[2]data[3]...data[n]
|
|
*
|
|
* The additional_info_ is in general a variable number of items, each
|
|
* is either a byte vector (e.g. std::vector<uint8_t>) or a string.
|
|
*
|
|
* n is the number of items. L[i] is the length of i th item. data[i]
|
|
* is the binary representation of the i th item
|
|
*
|
|
*/
|
|
namespace cuttlefish {
|
|
namespace confui {
|
|
namespace packet {
|
|
|
|
/*
|
|
* methods in namespace impl is not intended for public use
|
|
*
|
|
* For exposed APIs, skip to "start of public APIs
|
|
* or, skip the namespace impl
|
|
*/
|
|
namespace impl {
|
|
template <typename Buffer, typename... Args>
|
|
void AppendToBuffer(Buffer& buffer, Args&&... args) {
|
|
(buffer.insert(buffer.end(), std::begin(std::forward<Args>(args)),
|
|
std::end(std::forward<Args>(args))),
|
|
...);
|
|
}
|
|
|
|
template <typename... Args>
|
|
std::vector<int> MakeSizeHeader(Args&&... args) {
|
|
std::vector<int> lengths;
|
|
(lengths.push_back(std::distance(std::begin(args), std::end(args))), ...);
|
|
return lengths;
|
|
}
|
|
|
|
// Use only this function to make a packet to send over the confirmation
|
|
// ui packet layer
|
|
template <typename... Args>
|
|
Payload ToPayload(const std::string& cmd_str, const std::string& session_id,
|
|
Args&&... args) {
|
|
using namespace cuttlefish::confui::packet::impl;
|
|
constexpr auto n_args = sizeof...(Args);
|
|
std::stringstream ss;
|
|
ss << ArgsToString(session_id, ":", cmd_str, ":", n_args, ":");
|
|
// create size header
|
|
std::vector<int> size_info =
|
|
impl::MakeSizeHeader(std::forward<Args>(args)...);
|
|
for (const auto sz : size_info) {
|
|
ss << sz << ":";
|
|
}
|
|
std::string header = ss.str();
|
|
std::vector<std::uint8_t> payload_buffer{header.begin(), header.end()};
|
|
impl::AppendToBuffer(payload_buffer, std::forward<Args>(args)...);
|
|
|
|
PayloadHeader ph;
|
|
ph.payload_length_ = payload_buffer.size();
|
|
return {ph, payload_buffer};
|
|
}
|
|
} // namespace impl
|
|
|
|
/*
|
|
* start of public methods
|
|
*/
|
|
std::optional<ParsedPacket> ReadPayload(SharedFD s);
|
|
|
|
template <typename... Args>
|
|
bool WritePayload(SharedFD d, const std::string& cmd_str,
|
|
const std::string& session_id, Args&&... args) {
|
|
// TODO(kwstephenkim): type check Args... so that they are either
|
|
// kind of std::string or std::vector<1 byte>
|
|
if (!d->IsOpen()) {
|
|
ConfUiLog(ERROR) << "file, socket, etc, is not open to write";
|
|
return false;
|
|
}
|
|
auto [payload_header, data_to_send] =
|
|
impl::ToPayload(cmd_str, session_id, std::forward<Args>(args)...);
|
|
const std::string data_in_str(data_to_send.cbegin(), data_to_send.cend());
|
|
|
|
auto nwrite = WriteAll(d, reinterpret_cast<const char*>(&payload_header),
|
|
sizeof(payload_header));
|
|
if (nwrite != sizeof(payload_header)) {
|
|
return false;
|
|
}
|
|
nwrite = WriteAll(d, reinterpret_cast<const char*>(data_to_send.data()),
|
|
data_to_send.size());
|
|
if (nwrite != data_to_send.size()) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // end of namespace packet
|
|
} // end of namespace confui
|
|
} // end of namespace cuttlefish
|