blob: 43af3021a8fbd7c87e8fc7dfa147f8c17401c9c6 [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/shared/buffered_zx_socket.h"
#include "src/lib/fxl/logging.h"
#include "src/developer/debug/shared/message_loop_target.h"
#include "src/developer/debug/shared/zx_status.h"
namespace debug_ipc {
BufferedZxSocket::BufferedZxSocket() = default;
BufferedZxSocket::~BufferedZxSocket() = default;
zx_status_t BufferedZxSocket::Init(zx::socket socket) {
if (!socket.is_valid())
return ZX_ERR_INVALID_ARGS;
FXL_DCHECK(!socket_.is_valid()); // Can't be initialized more than once.
socket_ = std::move(socket);
stream_.set_writer(this);
return ZX_OK;
}
zx_status_t BufferedZxSocket::Start() {
if (!valid())
return ZX_ERR_BAD_STATE;
// Register for socket updates from the message loop.
MessageLoopTarget* loop = MessageLoopTarget::Current();
FXL_DCHECK(loop);
return loop->WatchSocket(MessageLoop::WatchMode::kReadWrite, socket_.get(),
this, &watch_handle_);
}
zx_status_t BufferedZxSocket::Stop() {
if (!valid() || watch_handle_.watching())
return ZX_ERR_BAD_STATE;
watch_handle_ = MessageLoop::WatchHandle();
return ZX_OK;
}
void BufferedZxSocket::Reset() {
socket_.reset();
callback_ = DataAvailableCallback();
error_callback_ = ErrorCallback();
}
void BufferedZxSocket::OnSocketReadable(zx_handle_t) {
// Messages from the client to the agent are typically small so we don't need
// a very large buffer.
constexpr size_t kBufSize = 1024;
// Add all available data to the socket buffer.
size_t msg_bytes = 0;
while (true) {
std::vector<char> buffer;
buffer.resize(kBufSize);
size_t num_read = 0;
zx_status_t status = socket_.read(0, &buffer[0], kBufSize, &num_read);
if (status == ZX_OK) {
msg_bytes += num_read;
buffer.resize(num_read);
stream_.AddReadData(std::move(buffer));
} else {
break;
}
// TODO(brettw) it would be nice to yield here after reading "a bunch" of
// data so this pipe doesn't starve the entire app.
}
// Some readable events don't have any bytes in them. Don't trigger the
// callback on those cases.
if (msg_bytes == 0)
return;
if (callback_)
callback_();
}
void BufferedZxSocket::OnSocketWritable(zx_handle_t) { stream_.SetWritable(); }
void BufferedZxSocket::OnSocketError(zx_handle_t) {
if (error_callback_)
error_callback_();
}
size_t BufferedZxSocket::ConsumeStreamBufferData(const char* data, size_t len) {
size_t written = 0;
socket_.write(0, data, len, &written);
return written;
}
} // namespace debug_ipc