brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 1 | // Copyright (c) 2012 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 | #ifndef IPC_IPC_CHANNEL_READER_H_ |
| 6 | #define IPC_IPC_CHANNEL_READER_H_ |
| 7 | |
avi | 42ebda4 | 2015-12-22 11:39:04 +0900 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 10 | #include <set> |
| 11 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 12 | #include "base/gtest_prod_util.h" |
tfarina | 2d565d3 | 2015-09-16 18:56:21 +0900 | [diff] [blame] | 13 | #include "base/macros.h" |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 14 | #include "ipc/ipc_channel.h" |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 15 | #include "ipc/ipc_export.h" |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 16 | |
| 17 | namespace IPC { |
| 18 | namespace internal { |
| 19 | |
| 20 | // This class provides common pipe reading functionality for the |
| 21 | // platform-specific IPC channel implementations. |
| 22 | // |
| 23 | // It does the common input buffer management and message dispatch, while the |
| 24 | // platform-specific parts provide the pipe management through a virtual |
| 25 | // interface implemented on a per-platform basis. |
| 26 | // |
| 27 | // Note that there is no "writer" corresponding to this because the code for |
| 28 | // writing to the channel is much simpler and has very little common |
| 29 | // functionality that would benefit from being factored out. If we add |
| 30 | // something like that in the future, it would be more appropriate to add it |
| 31 | // here (and rename appropriately) rather than writing a different class. |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 32 | class IPC_EXPORT ChannelReader { |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 33 | public: |
brettw@chromium.org | f947ed0 | 2012-06-12 07:35:26 +0900 | [diff] [blame] | 34 | explicit ChannelReader(Listener* listener); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 35 | virtual ~ChannelReader(); |
| 36 | |
brettw@chromium.org | f947ed0 | 2012-06-12 07:35:26 +0900 | [diff] [blame] | 37 | void set_listener(Listener* listener) { listener_ = listener; } |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 38 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 39 | // This type is returned by ProcessIncomingMessages to indicate the effect of |
| 40 | // the method. |
| 41 | enum DispatchState { |
| 42 | // All messages were successfully dispatched, or there were no messages to |
| 43 | // dispatch. |
| 44 | DISPATCH_FINISHED, |
| 45 | // There was a channel error. |
| 46 | DISPATCH_ERROR, |
| 47 | // Dispatching messages is blocked on receiving more information from the |
| 48 | // broker. |
| 49 | DISPATCH_WAITING_ON_BROKER, |
| 50 | }; |
| 51 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 52 | // Call to process messages received from the IPC connection and dispatch |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 53 | // them. |
| 54 | DispatchState ProcessIncomingMessages(); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 55 | |
| 56 | // Handles asynchronously read data. |
| 57 | // |
| 58 | // Optionally call this after returning READ_PENDING from ReadData to |
| 59 | // indicate that buffer was filled with the given number of bytes of |
| 60 | // data. See ReadData for more. |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 61 | DispatchState AsyncReadComplete(int bytes_read); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 62 | |
hubbe@chromium.org | 683920d | 2013-10-15 09:07:00 +0900 | [diff] [blame] | 63 | // Returns true if the given message is internal to the IPC implementation, |
| 64 | // like the "hello" message sent on channel set-up. |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 65 | bool IsInternalMessage(const Message& m); |
hubbe@chromium.org | 683920d | 2013-10-15 09:07:00 +0900 | [diff] [blame] | 66 | |
| 67 | // Returns true if the given message is an Hello message |
| 68 | // sent on channel set-up. |
morrita@chromium.org | 15996aa | 2014-08-05 08:44:17 +0900 | [diff] [blame] | 69 | bool IsHelloMessage(const Message& m); |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 70 | |
| 71 | protected: |
| 72 | enum ReadState { READ_SUCCEEDED, READ_FAILED, READ_PENDING }; |
| 73 | |
brettw@chromium.org | f947ed0 | 2012-06-12 07:35:26 +0900 | [diff] [blame] | 74 | Listener* listener() const { return listener_; } |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 75 | |
erikchen | 133c289 | 2015-09-12 02:33:34 +0900 | [diff] [blame] | 76 | // Subclasses should call this method in their destructor to give this class a |
| 77 | // chance to clean up state that might be dependent on subclass members. |
| 78 | void CleanUp(); |
| 79 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 80 | // Populates the given buffer with data from the pipe. |
| 81 | // |
| 82 | // Returns the state of the read. On READ_SUCCESS, the number of bytes |
| 83 | // read will be placed into |*bytes_read| (which can be less than the |
| 84 | // buffer size). On READ_FAILED, the channel will be closed. |
| 85 | // |
| 86 | // If the return value is READ_PENDING, it means that there was no data |
| 87 | // ready for reading. The implementation is then responsible for either |
| 88 | // calling AsyncReadComplete with the number of bytes read into the |
| 89 | // buffer, or ProcessIncomingMessages to try the read again (depending |
| 90 | // on whether the platform's async I/O is "try again" or "write |
| 91 | // asynchronously into your buffer"). |
| 92 | virtual ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) = 0; |
| 93 | |
| 94 | // Loads the required file desciptors into the given message. Returns true |
| 95 | // on success. False means a fatal channel error. |
| 96 | // |
| 97 | // This will read from the input_fds_ and read more handles from the FD |
| 98 | // pipe if necessary. |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 99 | virtual bool ShouldDispatchInputMessage(Message* msg) = 0; |
| 100 | |
| 101 | // Overridden by subclasses to get attachments that are sent alongside the IPC |
sammc | 1458336 | 2016-11-23 12:17:35 +0900 | [diff] [blame] | 102 | // channel. |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 103 | // Returns true on success. False means a fatal channel error. |
sammc | 1458336 | 2016-11-23 12:17:35 +0900 | [diff] [blame] | 104 | virtual bool GetAttachments(Message* msg) = 0; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 105 | |
| 106 | // Performs post-dispatch checks. Called when all input buffers are empty, |
| 107 | // though there could be more data ready to be read from the OS. |
| 108 | virtual bool DidEmptyInputBuffers() = 0; |
| 109 | |
hubbe@chromium.org | 683920d | 2013-10-15 09:07:00 +0900 | [diff] [blame] | 110 | // Handles internal messages, like the hello message sent on channel startup. |
| 111 | virtual void HandleInternalMessage(const Message& msg) = 0; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 112 | |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 113 | // Exposed for testing purposes only. |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 114 | virtual void DispatchMessage(Message* m); |
| 115 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 116 | private: |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 117 | FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, AttachmentAlreadyBrokered); |
| 118 | FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, AttachmentNotYetBrokered); |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 119 | FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, ResizeOverflowBuffer); |
| 120 | FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, InvalidMessageSize); |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 121 | FRIEND_TEST_ALL_PREFIXES(ChannelReaderTest, TrimBuffer); |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 122 | |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 123 | // Takes the data received from the IPC channel and translates it into |
| 124 | // Messages. Complete messages are passed to HandleTranslatedMessage(). |
| 125 | // Returns |false| on unrecoverable error. |
erikchen | f295bbc | 2015-07-28 03:26:14 +0900 | [diff] [blame] | 126 | bool TranslateInputData(const char* input_data, int input_data_len); |
| 127 | |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 128 | // Internal messages and messages bound for the attachment broker are |
| 129 | // immediately dispatched. Other messages are passed to |
| 130 | // HandleExternalMessage(). |
| 131 | // Returns |false| on unrecoverable error. |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 132 | bool HandleTranslatedMessage(Message* translated_message); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 133 | |
| 134 | // Populates the message with brokered and non-brokered attachments. If |
| 135 | // possible, the message is immediately dispatched. Otherwise, a deep copy of |
| 136 | // the message is added to |queued_messages_|. |blocked_ids_| are updated if |
| 137 | // necessary. |
sammc | c54b4e9 | 2016-11-09 08:24:35 +0900 | [diff] [blame] | 138 | bool HandleExternalMessage(Message* external_message); |
erikchen | 2c0e5dc | 2015-10-22 07:28:54 +0900 | [diff] [blame] | 139 | |
| 140 | // If there was a dispatch error, informs |listener_|. |
| 141 | void HandleDispatchError(const Message& message); |
| 142 | |
dskiba | aa08dcb | 2015-10-01 02:24:30 +0900 | [diff] [blame] | 143 | // Checks that |size| is a valid message size. Has side effects if it's not. |
| 144 | bool CheckMessageSize(size_t size); |
| 145 | |
brettw@chromium.org | f947ed0 | 2012-06-12 07:35:26 +0900 | [diff] [blame] | 146 | Listener* listener_; |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 147 | |
| 148 | // We read from the pipe into this buffer. Managed by DispatchInputData, do |
| 149 | // not access directly outside that function. |
| 150 | char input_buf_[Channel::kReadBufferSize]; |
| 151 | |
| 152 | // Large messages that span multiple pipe buffers, get built-up using |
| 153 | // this buffer. |
| 154 | std::string input_overflow_buf_; |
| 155 | |
dskiba | 905b9b9 | 2015-11-04 10:24:59 +0900 | [diff] [blame] | 156 | // Maximum overflow buffer size, see Channel::kMaximumReadBufferSize. |
| 157 | // This is not a constant because we update it to reflect the reality |
| 158 | // of std::string::reserve() implementation. |
| 159 | size_t max_input_buffer_size_; |
| 160 | |
brettw@chromium.org | 0e9d0a1 | 2012-03-08 21:30:28 +0900 | [diff] [blame] | 161 | DISALLOW_COPY_AND_ASSIGN(ChannelReader); |
| 162 | }; |
| 163 | |
| 164 | } // namespace internal |
| 165 | } // namespace IPC |
| 166 | |
| 167 | #endif // IPC_IPC_CHANNEL_READER_H_ |