1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169

ipc / ipc_channel_reader.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IPC_IPC_CHANNEL_READER_H_
#define IPC_IPC_CHANNEL_READER_H_

#include <stddef.h>

#include <set>

#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "ipc/ipc_channel.h"

namespace IPC {
namespace internal {

// This class provides common pipe reading functionality for the
// platform-specific IPC channel implementations.
//
// It does the common input buffer management and message dispatch, while the
// platform-specific parts provide the pipe management through a virtual
// interface implemented on a per-platform basis.
//
// Note that there is no "writer" corresponding to this because the code for
// writing to the channel is much simpler and has very little common
// functionality that would benefit from being factored out. If we add
// something like that in the future, it would be more appropriate to add it
// here (and rename appropriately) rather than writing a different class.
class COMPONENT_EXPORT(IPC) ChannelReader {
 public:
  explicit ChannelReader(Listener* listener);

  ChannelReader(const ChannelReader&) = delete;
  ChannelReader& operator=(const ChannelReader&) = delete;

  virtual ~ChannelReader();

  void set_listener(Listener* listener) { listener_ = listener; }

  // This type is returned by ProcessIncomingMessages to indicate the effect of
  // the method.
  enum DispatchState {
    // All messages were successfully dispatched, or there were no messages to
    // dispatch.
    DISPATCH_FINISHED,
    // There was a channel error.
    DISPATCH_ERROR,
    // Dispatching messages is blocked on receiving more information from the
    // broker.
    DISPATCH_WAITING_ON_BROKER,
  };

  // Call to process messages received from the IPC connection and dispatch
  // them.
  DispatchState ProcessIncomingMessages();

  // Handles asynchronously read data.
  //
  // Optionally call this after returning READ_PENDING from ReadData to
  // indicate that buffer was filled with the given number of bytes of
  // data. See ReadData for more.
  DispatchState AsyncReadComplete(int bytes_read);

  // Returns true if the given message is internal to the IPC implementation,
  // like the "hello" message sent on channel set-up.
  bool IsInternalMessage(const Message& m);

  // Returns true if the given message is an Hello message
  // sent on channel set-up.
  bool IsHelloMessage(const Message& m);

 protected:
  enum ReadState { READ_SUCCEEDED, READ_FAILED, READ_PENDING };

  Listener* listener() const { return listener_; }

  // Subclasses should call this method in their destructor to give this class a
  // chance to clean up state that might be dependent on subclass members.
  void CleanUp();

  // Populates the given buffer with data from the pipe.
  //
  // Returns the state of the read. On READ_SUCCESS, the number of bytes
  // read will be placed into |*bytes_read| (which can be less than the
  // buffer size). On READ_FAILED, the channel will be closed.
  //
  // If the return value is READ_PENDING, it means that there was no data
  // ready for reading. The implementation is then responsible for either
  // calling AsyncReadComplete with the number of bytes read into the
  // buffer, or ProcessIncomingMessages to try the read again (depending
  // on whether the platform's async I/O is "try again" or "write
  // asynchronously into your buffer").
  virtual ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) = 0;

  // Loads the required file desciptors into the given message. Returns true
  // on success. False means a fatal channel error.
  //
  // This will read from the input_fds_ and read more handles from the FD
  // pipe if necessary.
  virtual bool ShouldDispatchInputMessage(Message* msg) = 0;

  // Overridden by subclasses to get attachments that are sent alongside the IPC
  // channel.
  // Returns true on success. False means a fatal channel error.
  virtual bool GetAttachments(Message* msg) = 0;

  // Performs post-dispatch checks. Called when all input buffers are empty,
  // though there could be more data ready to be read from the OS.
  virtual bool DidEmptyInputBuffers() = 0;

  // Handles internal messages, like the hello message sent on channel startup.
  virtual void HandleInternalMessage(const Message& msg) = 0;

  // Exposed for testing purposes only.
  virtual void DispatchMessage(Message* m);

 private:
  FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, AttachmentAlreadyBrokered);
  FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, AttachmentNotYetBrokered);
  FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, ResizeOverflowBuffer);
  FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, InvalidMessageSize);
  FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, TrimBuffer);

  // Takes the data received from the IPC channel and translates it into
  // Messages. Complete messages are passed to HandleTranslatedMessage().
  // Returns |false| on unrecoverable error.
  bool TranslateInputData(const char* input_data, int input_data_len);

  // Internal messages and messages bound for the attachment broker are
  // immediately dispatched. Other messages are passed to
  // HandleExternalMessage().
  // Returns |false| on unrecoverable error.
  bool HandleTranslatedMessage(Message* translated_message);

  // Populates the message with brokered and non-brokered attachments. If
  // possible, the message is immediately dispatched. Otherwise, a deep copy of
  // the message is added to |queued_messages_|. |blocked_ids_| are updated if
  // necessary.
  bool HandleExternalMessage(Message* external_message);

  // If there was a dispatch error, informs |listener_|.
  void HandleDispatchError(const Message& message);

  // Checks that |size| is a valid message size. Has side effects if it's not.
  bool CheckMessageSize(size_t size);

  raw_ptr<Listener> listener_;

  // We read from the pipe into this buffer. Managed by DispatchInputData, do
  // not access directly outside that function.
  char input_buf_[Channel::kReadBufferSize];

  // Large messages that span multiple pipe buffers, get built-up using
  // this buffer.
  std::string input_overflow_buf_;

  // Maximum overflow buffer size, see Channel::kMaximumReadBufferSize.
  // This is not a constant because we update it to reflect the reality
  // of std::string::reserve() implementation.
  size_t max_input_buffer_size_;
};

}  // namespace internal
}  // namespace IPC

#endif  // IPC_IPC_CHANNEL_READER_H_