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