1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/dbus/pipe_reader.h"
6
7#include "base/bind.h"
8#include "base/posix/eintr_wrapper.h"
9#include "base/task_runner.h"
10#include "net/base/file_stream.h"
11#include "net/base/io_buffer.h"
12#include "net/base/net_errors.h"
13
14namespace chromeos {
15
16PipeReader::PipeReader(const scoped_refptr<base::TaskRunner>& task_runner,
17                       const IOCompleteCallback& callback)
18    : io_buffer_(new net::IOBufferWithSize(4096)),
19      task_runner_(task_runner),
20      callback_(callback),
21      weak_ptr_factory_(this) {}
22
23PipeReader::~PipeReader() {
24}
25
26base::File PipeReader::StartIO() {
27  // Use a pipe to collect data
28  int pipe_fds[2];
29  const int status = HANDLE_EINTR(pipe(pipe_fds));
30  if (status < 0) {
31    PLOG(ERROR) << "pipe";
32    return base::File();
33  }
34  base::File pipe_write_end(pipe_fds[1]);
35  // Pass ownership of pipe_fds[0] to data_stream_, which will close it.
36  data_stream_.reset(new net::FileStream(
37      base::File(pipe_fds[0]), task_runner_));
38
39  // Post an initial async read to setup data collection
40  int rv = data_stream_->Read(
41      io_buffer_.get(), io_buffer_->size(),
42      base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
43  if (rv != net::ERR_IO_PENDING) {
44    LOG(ERROR) << "Unable to post initial read";
45    return base::File();
46  }
47  return pipe_write_end.Pass();
48}
49
50void PipeReader::OnDataReady(int byte_count) {
51  DVLOG(1) << "OnDataReady byte_count " << byte_count;
52  if (byte_count <= 0) {
53    callback_.Run();  // signal creator to take data and delete us
54    return;
55  }
56
57  AcceptData(io_buffer_->data(), byte_count);
58
59  // Post another read
60  int rv = data_stream_->Read(
61      io_buffer_.get(), io_buffer_->size(),
62      base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
63  if (rv != net::ERR_IO_PENDING) {
64    LOG(ERROR) << "Unable to post another read";
65    // TODO(sleffler) do something more intelligent?
66  }
67}
68
69PipeReaderForString::PipeReaderForString(
70    const scoped_refptr<base::TaskRunner>& task_runner,
71    const IOCompleteCallback& callback)
72    : PipeReader(task_runner, callback) {
73}
74
75void PipeReaderForString::AcceptData(const char *data, int byte_count) {
76  data_.append(data, byte_count);
77}
78
79void PipeReaderForString::GetData(std::string* data) {
80  data_.swap(*data);
81}
82
83}  // namespace chromeos
84