// Copyright 2014 The Chromium 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 "chromeos/dbus/pipe_reader.h"
#include "base/bind.h"
#include "base/posix/eintr_wrapper.h"
#include "base/task_runner.h"
#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
namespace chromeos {
PipeReader::PipeReader(const scoped_refptr<base::TaskRunner>& task_runner,
const IOCompleteCallback& callback)
: io_buffer_(new net::IOBufferWithSize(4096)),
task_runner_(task_runner),
callback_(callback),
weak_ptr_factory_(this) {}
PipeReader::~PipeReader() {
}
base::File PipeReader::StartIO() {
// Use a pipe to collect data
int pipe_fds[2];
const int status = HANDLE_EINTR(pipe(pipe_fds));
if (status < 0) {
PLOG(ERROR) << "pipe";
return base::File();
}
base::File pipe_write_end(pipe_fds[1]);
// Pass ownership of pipe_fds[0] to data_stream_, which will close it.
data_stream_.reset(new net::FileStream(
base::File(pipe_fds[0]), task_runner_));
// Post an initial async read to setup data collection
int rv = data_stream_->Read(
io_buffer_.get(), io_buffer_->size(),
base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING) {
LOG(ERROR) << "Unable to post initial read";
return base::File();
}
return pipe_write_end.Pass();
}
void PipeReader::OnDataReady(int byte_count) {
DVLOG(1) << "OnDataReady byte_count " << byte_count;
if (byte_count <= 0) {
callback_.Run(); // signal creator to take data and delete us
return;
}
AcceptData(io_buffer_->data(), byte_count);
// Post another read
int rv = data_stream_->Read(
io_buffer_.get(), io_buffer_->size(),
base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
if (rv != net::ERR_IO_PENDING) {
LOG(ERROR) << "Unable to post another read";
// TODO(sleffler) do something more intelligent?
}
}
PipeReaderForString::PipeReaderForString(
const scoped_refptr<base::TaskRunner>& task_runner,
const IOCompleteCallback& callback)
: PipeReader(task_runner, callback) {
}
void PipeReaderForString::AcceptData(const char *data, int byte_count) {
data_.append(data, byte_count);
}
void PipeReaderForString::GetData(std::string* data) {
data_.swap(*data);
}
} // namespace chromeos