| // 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 |