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