blob: f16bf537178b957227110c7d8064bdf53e85dd16 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/debug_agent/remote_api_adapter.h"
#include "src/developer/debug/debug_agent/remote_api.h"
#include "src/developer/debug/ipc/message_reader.h"
#include "src/developer/debug/ipc/message_writer.h"
#include "src/developer/debug/ipc/protocol.h"
#include "src/developer/debug/shared/logging/logging.h"
#include "src/developer/debug/shared/stream_buffer.h"
namespace debug_agent {
namespace {
// Deserializes the request based on type, calls the given hander in the
// RemoteAPI, and then sends the reply back to the client.
template <typename RequestMsg, typename ReplyMsg>
void DispatchMessage(RemoteAPIAdapter* adapter,
void (RemoteAPI::*handler)(const RequestMsg&, ReplyMsg*),
std::vector<char> data, const char* type_string) {
RequestMsg request;
uint32_t transaction_id = 0;
if (!debug_ipc::Deserialize(std::move(data), &request, &transaction_id,
adapter->api()->GetVersion())) {
LOGS(Error) << "Got bad debugger " << type_string << "Request, ignoring.";
return;
}
ReplyMsg reply;
(adapter->api()->*handler)(request, &reply);
// Re-get the version after processing the handler. For the "hello" message, the version is set
// during processing of the message.
adapter->stream()->Write(
debug_ipc::Serialize(reply, transaction_id, adapter->api()->GetVersion()));
}
} // namespace
RemoteAPIAdapter::RemoteAPIAdapter(RemoteAPI* remote_api, debug::StreamBuffer* stream)
: api_(remote_api), stream_(stream) {}
void RemoteAPIAdapter::OnStreamReadable() {
if (!api_ || !stream_) {
LOGS(Error) << "Attempt to call OnStreamReadable with invalid RemoteAPI or StreamBuffer!";
return;
}
while (true) {
debug_ipc::MsgHeader header;
size_t bytes_read = stream_->Peek(reinterpret_cast<char*>(&header), sizeof(header));
if (bytes_read != sizeof(header))
return; // Don't have enough data for the header.
if (!stream_->IsAvailable(header.size))
return; // Entire message hasn't arrived yet.
// The message size includes the header.
std::vector<char> buffer(header.size);
stream_->Read(buffer.data(), header.size);
switch (header.type) {
// Dispatches a message type assuming the handler function name, request
// struct type, and reply struct type are all based on the message type name.
// For example, MsgHeader::Type::kFoo will call:
// api->OnFoo(FooRequest, FooReply*);
#define DISPATCH(msg_type) \
case debug_ipc::MsgHeader::Type::k##msg_type: \
DispatchMessage<debug_ipc::msg_type##Request, debug_ipc::msg_type##Reply>( \
this, &RemoteAPI::On##msg_type, std::move(buffer), #msg_type); \
break;
FOR_EACH_REQUEST_TYPE(DISPATCH)
#undef DISPATCH
default:
// Unknown message type.
LOGS(Error) << "Invalid message type " << static_cast<uint32_t>(header.type)
<< ", ignoring.";
break;
}
}
}
} // namespace debug_agent