Jakub Pawlowski | 86aa225 | 2017-04-05 09:22:29 -0700 | [diff] [blame] | 1 | // Copyright 2016 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 MOJO_CORE_CHANNEL_H_ |
| 6 | #define MOJO_CORE_CHANNEL_H_ |
| 7 | |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "base/macros.h" |
| 11 | #include "base/memory/ref_counted.h" |
| 12 | #include "base/process/process_handle.h" |
| 13 | #include "base/task_runner.h" |
| 14 | #include "build/build_config.h" |
| 15 | #include "mojo/core/connection_params.h" |
| 16 | #include "mojo/core/platform_handle_in_transit.h" |
| 17 | #include "mojo/core/scoped_process_handle.h" |
| 18 | #include "mojo/public/cpp/platform/platform_handle.h" |
| 19 | |
| 20 | namespace mojo { |
| 21 | namespace core { |
| 22 | |
| 23 | const size_t kChannelMessageAlignment = 8; |
| 24 | |
| 25 | constexpr bool IsAlignedForChannelMessage(size_t n) { |
| 26 | return n % kChannelMessageAlignment == 0; |
| 27 | } |
| 28 | |
| 29 | // Channel provides a thread-safe interface to read and write arbitrary |
| 30 | // delimited messages over an underlying I/O channel, optionally transferring |
| 31 | // one or more platform handles in the process. |
| 32 | class MOJO_SYSTEM_IMPL_EXPORT Channel |
| 33 | : public base::RefCountedThreadSafe<Channel> { |
| 34 | public: |
| 35 | struct Message; |
| 36 | |
| 37 | using MessagePtr = std::unique_ptr<Message>; |
| 38 | |
| 39 | // A message to be written to a channel. |
| 40 | struct MOJO_SYSTEM_IMPL_EXPORT Message { |
| 41 | enum class MessageType : uint16_t { |
| 42 | // An old format normal message, that uses the LegacyHeader. |
| 43 | // Only used on Android and ChromeOS. |
| 44 | // TODO(https://crbug.com/695645): remove legacy support when Arc++ has |
| 45 | // updated to Mojo with normal versioned messages. |
| 46 | NORMAL_LEGACY = 0, |
| 47 | #if defined(OS_MACOSX) |
| 48 | // A control message containing handles to echo back. |
| 49 | HANDLES_SENT, |
| 50 | // A control message containing handles that can now be closed. |
| 51 | HANDLES_SENT_ACK, |
| 52 | #endif |
| 53 | // A normal message that uses Header and can contain extra header values. |
| 54 | NORMAL, |
| 55 | }; |
| 56 | |
| 57 | #pragma pack(push, 1) |
| 58 | // Old message wire format for ChromeOS and Android, used by NORMAL_LEGACY |
| 59 | // messages. |
| 60 | struct LegacyHeader { |
| 61 | // Message size in bytes, including the header. |
| 62 | uint32_t num_bytes; |
| 63 | |
| 64 | // Number of attached handles. |
| 65 | uint16_t num_handles; |
| 66 | |
| 67 | MessageType message_type; |
| 68 | }; |
| 69 | |
| 70 | // Header used by NORMAL messages. |
| 71 | // To preserve backward compatibility with LegacyHeader, the num_bytes and |
| 72 | // message_type field must be at the same offset as in LegacyHeader. |
| 73 | struct Header { |
| 74 | // Message size in bytes, including the header. |
| 75 | uint32_t num_bytes; |
| 76 | |
| 77 | // Total size of header, including extra header data (i.e. HANDLEs on |
| 78 | // windows). |
| 79 | uint16_t num_header_bytes; |
| 80 | |
| 81 | MessageType message_type; |
| 82 | |
| 83 | // Number of attached handles. May be less than the reserved handle |
| 84 | // storage size in this message on platforms that serialise handles as |
| 85 | // data (i.e. HANDLEs on Windows, Mach ports on OSX). |
| 86 | uint16_t num_handles; |
| 87 | |
| 88 | char padding[6]; |
| 89 | }; |
| 90 | |
| 91 | #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 92 | struct MachPortsEntry { |
| 93 | // Index of Mach port in the original vector of PlatformHandleInTransits. |
| 94 | uint16_t index; |
| 95 | |
| 96 | // Mach port name. |
| 97 | uint32_t mach_port; |
| 98 | static_assert(sizeof(mach_port_t) <= sizeof(uint32_t), |
| 99 | "mach_port_t must be no larger than uint32_t"); |
| 100 | }; |
| 101 | static_assert(sizeof(MachPortsEntry) == 6, |
| 102 | "sizeof(MachPortsEntry) must be 6 bytes"); |
| 103 | |
| 104 | // Structure of the extra header field when present on OSX. |
| 105 | struct MachPortsExtraHeader { |
| 106 | // Actual number of Mach ports encoded in the extra header. |
| 107 | uint16_t num_ports; |
| 108 | |
| 109 | // Array of encoded Mach ports. If |num_ports| > 0, |entries[0]| through |
| 110 | // to |entries[num_ports-1]| inclusive are valid. |
| 111 | MachPortsEntry entries[0]; |
| 112 | }; |
| 113 | static_assert(sizeof(MachPortsExtraHeader) == 2, |
| 114 | "sizeof(MachPortsExtraHeader) must be 2 bytes"); |
| 115 | #elif defined(OS_FUCHSIA) |
| 116 | struct HandleInfoEntry { |
| 117 | // The FDIO type associated with one or more handles, or zero for handles |
| 118 | // that do not belong to FDIO. |
| 119 | uint8_t type; |
| 120 | // Zero for non-FDIO handles, otherwise the number of handles to consume |
| 121 | // to generate an FDIO file-descriptor wrapper. |
| 122 | uint8_t count; |
| 123 | }; |
| 124 | #elif defined(OS_WIN) |
| 125 | struct HandleEntry { |
| 126 | // The windows HANDLE. HANDLEs are guaranteed to fit inside 32-bits. |
| 127 | // See: https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx |
| 128 | uint32_t handle; |
| 129 | }; |
| 130 | static_assert(sizeof(HandleEntry) == 4, |
| 131 | "sizeof(HandleEntry) must be 4 bytes"); |
| 132 | #endif |
| 133 | #pragma pack(pop) |
| 134 | |
| 135 | // Allocates and owns a buffer for message data with enough capacity for |
| 136 | // |payload_size| bytes plus a header, plus |max_handles| platform handles. |
| 137 | Message(size_t payload_size, size_t max_handles); |
| 138 | Message(size_t payload_size, size_t max_handles, MessageType message_type); |
| 139 | Message(size_t capacity, size_t payload_size, size_t max_handles); |
| 140 | Message(size_t capacity, |
| 141 | size_t max_handles, |
| 142 | size_t payload_size, |
| 143 | MessageType message_type); |
| 144 | ~Message(); |
| 145 | |
| 146 | // Constructs a Message from serialized message data, optionally coming from |
| 147 | // a known remote process. |
| 148 | static MessagePtr Deserialize( |
| 149 | const void* data, |
| 150 | size_t data_num_bytes, |
| 151 | base::ProcessHandle from_process = base::kNullProcessHandle); |
| 152 | |
| 153 | const void* data() const { return data_; } |
| 154 | size_t data_num_bytes() const { return size_; } |
| 155 | |
| 156 | // The current capacity of the message buffer, not counting internal header |
| 157 | // data. |
| 158 | size_t capacity() const; |
| 159 | |
| 160 | // Extends the portion of the total message capacity which contains |
| 161 | // meaningful payload data. Storage capacity which falls outside of this |
| 162 | // range is not transmitted when the message is sent. |
| 163 | // |
| 164 | // If the message's current capacity is not large enough to accommodate the |
| 165 | // new payload size, it will be reallocated accordingly. |
| 166 | void ExtendPayload(size_t new_payload_size); |
| 167 | |
| 168 | const void* extra_header() const; |
| 169 | void* mutable_extra_header(); |
| 170 | size_t extra_header_size() const; |
| 171 | |
| 172 | void* mutable_payload(); |
| 173 | const void* payload() const; |
| 174 | size_t payload_size() const; |
| 175 | |
| 176 | size_t num_handles() const; |
| 177 | bool has_handles() const; |
| 178 | #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 179 | bool has_mach_ports() const; |
| 180 | #endif |
| 181 | |
| 182 | bool is_legacy_message() const; |
| 183 | LegacyHeader* legacy_header() const; |
| 184 | Header* header() const; |
| 185 | |
| 186 | // Note: SetHandles() and TakeHandles() invalidate any previous value of |
| 187 | // handles(). |
| 188 | void SetHandles(std::vector<PlatformHandle> new_handles); |
| 189 | void SetHandles(std::vector<PlatformHandleInTransit> new_handles); |
| 190 | std::vector<PlatformHandleInTransit> TakeHandles(); |
| 191 | // Version of TakeHandles that returns a vector of platform handles suitable |
| 192 | // for transfer over an underlying OS mechanism. i.e. file descriptors over |
| 193 | // a unix domain socket. Any handle that cannot be transferred this way, |
| 194 | // such as Mach ports, will be removed. |
| 195 | std::vector<PlatformHandleInTransit> TakeHandlesForTransport(); |
| 196 | |
| 197 | void SetVersionForTest(uint16_t version_number); |
| 198 | |
| 199 | private: |
| 200 | // The message data buffer. |
| 201 | char* data_ = nullptr; |
| 202 | |
| 203 | // The capacity of the buffer at |data_|. |
| 204 | size_t capacity_ = 0; |
| 205 | |
| 206 | // The size of the message. This is the portion of |data_| that should |
| 207 | // be transmitted if the message is written to a channel. Includes all |
| 208 | // headers and user payload. |
| 209 | size_t size_ = 0; |
| 210 | |
| 211 | // Maximum number of handles which may be attached to this message. |
| 212 | size_t max_handles_ = 0; |
| 213 | |
| 214 | std::vector<PlatformHandleInTransit> handle_vector_; |
| 215 | |
| 216 | #if defined(OS_WIN) |
| 217 | // On Windows, handles are serialised into the extra header section. |
| 218 | HandleEntry* handles_ = nullptr; |
| 219 | #elif defined(OS_MACOSX) && !defined(OS_IOS) |
| 220 | // On OSX, handles are serialised into the extra header section. |
| 221 | MachPortsExtraHeader* mach_ports_header_ = nullptr; |
| 222 | #endif |
| 223 | |
| 224 | DISALLOW_COPY_AND_ASSIGN(Message); |
| 225 | }; |
| 226 | |
| 227 | // Error types which may be reported by a Channel instance to its delegate. |
| 228 | enum class Error { |
| 229 | // The remote end of the channel has been closed, either explicitly or |
| 230 | // because the process which hosted it is gone. |
| 231 | kDisconnected, |
| 232 | |
| 233 | // For connection-oriented channels (e.g. named pipes), an unexpected error |
| 234 | // occurred during channel connection. |
| 235 | kConnectionFailed, |
| 236 | |
| 237 | // Some incoming data failed validation, implying either a buggy or |
| 238 | // compromised sender. |
| 239 | kReceivedMalformedData, |
| 240 | }; |
| 241 | |
| 242 | // Delegate methods are called from the I/O task runner with which the Channel |
| 243 | // was created (see Channel::Create). |
| 244 | class Delegate { |
| 245 | public: |
| 246 | virtual ~Delegate() {} |
| 247 | |
| 248 | // Notify of a received message. |payload| is not owned and must not be |
| 249 | // retained; it will be null if |payload_size| is 0. |handles| are |
| 250 | // transferred to the callee. |
| 251 | virtual void OnChannelMessage(const void* payload, |
| 252 | size_t payload_size, |
| 253 | std::vector<PlatformHandle> handles) = 0; |
| 254 | |
| 255 | // Notify that an error has occured and the Channel will cease operation. |
| 256 | virtual void OnChannelError(Error error) = 0; |
| 257 | }; |
| 258 | |
| 259 | // Creates a new Channel around a |platform_handle|, taking ownership of the |
| 260 | // handle. All I/O on the handle will be performed on |io_task_runner|. |
| 261 | // Note that ShutDown() MUST be called on the Channel some time before |
| 262 | // |delegate| is destroyed. |
| 263 | static scoped_refptr<Channel> Create( |
| 264 | Delegate* delegate, |
| 265 | ConnectionParams connection_params, |
| 266 | scoped_refptr<base::TaskRunner> io_task_runner); |
| 267 | |
| 268 | // Request that the channel be shut down. This should always be called before |
| 269 | // releasing the last reference to a Channel to ensure that it's cleaned up |
| 270 | // on its I/O task runner's thread. |
| 271 | // |
| 272 | // Delegate methods will no longer be invoked after this call. |
| 273 | void ShutDown(); |
| 274 | |
| 275 | // Sets the process handle of the remote endpoint to which this Channel is |
| 276 | // connected. If called at all, must be called only once, and before Start(). |
| 277 | void set_remote_process(ScopedProcessHandle remote_process) { |
| 278 | DCHECK(!remote_process_.is_valid()); |
| 279 | remote_process_ = std::move(remote_process); |
| 280 | } |
| 281 | const ScopedProcessHandle& remote_process() const { return remote_process_; } |
| 282 | |
| 283 | // Begin processing I/O events. Delegate methods must only be invoked after |
| 284 | // this call. |
| 285 | virtual void Start() = 0; |
| 286 | |
| 287 | // Stop processing I/O events. |
| 288 | virtual void ShutDownImpl() = 0; |
| 289 | |
| 290 | // Queues an outgoing message on the Channel. This message will either |
| 291 | // eventually be written or will fail to write and trigger |
| 292 | // Delegate::OnChannelError. |
| 293 | virtual void Write(MessagePtr message) = 0; |
| 294 | |
| 295 | // Causes the platform handle to leak when this channel is shut down instead |
| 296 | // of closing it. |
| 297 | virtual void LeakHandle() = 0; |
| 298 | |
| 299 | protected: |
| 300 | explicit Channel(Delegate* delegate); |
| 301 | virtual ~Channel(); |
| 302 | |
| 303 | Delegate* delegate() const { return delegate_; } |
| 304 | |
| 305 | // Called by the implementation when it wants somewhere to stick data. |
| 306 | // |*buffer_capacity| may be set by the caller to indicate the desired buffer |
| 307 | // size. If 0, a sane default size will be used instead. |
| 308 | // |
| 309 | // Returns the address of a buffer which can be written to, and indicates its |
| 310 | // actual capacity in |*buffer_capacity|. |
| 311 | char* GetReadBuffer(size_t* buffer_capacity); |
| 312 | |
| 313 | // Called by the implementation when new data is available in the read |
| 314 | // buffer. Returns false to indicate an error. Upon success, |
| 315 | // |*next_read_size_hint| will be set to a recommended size for the next |
| 316 | // read done by the implementation. |
| 317 | bool OnReadComplete(size_t bytes_read, size_t* next_read_size_hint); |
| 318 | |
| 319 | // Called by the implementation when something goes horribly wrong. It is NOT |
| 320 | // OK to call this synchronously from any public interface methods. |
| 321 | void OnError(Error error); |
| 322 | |
| 323 | // Retrieves the set of platform handles read for a given message. |
| 324 | // |extra_header| and |extra_header_size| correspond to the extra header data. |
| 325 | // Depending on the Channel implementation, this body may encode platform |
| 326 | // handles, or handles may be stored and managed elsewhere by the |
| 327 | // implementation. |
| 328 | // |
| 329 | // Returns |false| on unrecoverable error (i.e. the Channel should be closed). |
| 330 | // Returns |true| otherwise. Note that it is possible on some platforms for an |
| 331 | // insufficient number of handles to be available when this call is made, but |
| 332 | // this is not necessarily an error condition. In such cases this returns |
| 333 | // |true| but |*handles| will also be reset to null. |
| 334 | // |
| 335 | // If the implementation sets |*deferred| to |true|, it assumes responsibility |
| 336 | // for dispatching the message eventually. It must copy |payload| to retain |
| 337 | // it for later transmission. |
| 338 | virtual bool GetReadPlatformHandles(const void* payload, |
| 339 | size_t payload_size, |
| 340 | size_t num_handles, |
| 341 | const void* extra_header, |
| 342 | size_t extra_header_size, |
| 343 | std::vector<PlatformHandle>* handles, |
| 344 | bool* deferred) = 0; |
| 345 | |
| 346 | // Handles a received control message. Returns |true| if the message is |
| 347 | // accepted, or |false| otherwise. |
| 348 | virtual bool OnControlMessage(Message::MessageType message_type, |
| 349 | const void* payload, |
| 350 | size_t payload_size, |
| 351 | std::vector<PlatformHandle> handles); |
| 352 | |
| 353 | private: |
| 354 | friend class base::RefCountedThreadSafe<Channel>; |
| 355 | |
| 356 | class ReadBuffer; |
| 357 | |
| 358 | Delegate* delegate_; |
| 359 | const std::unique_ptr<ReadBuffer> read_buffer_; |
| 360 | |
| 361 | // Handle to the process on the other end of this Channel, iff known. |
| 362 | ScopedProcessHandle remote_process_; |
| 363 | |
| 364 | DISALLOW_COPY_AND_ASSIGN(Channel); |
| 365 | }; |
| 366 | |
| 367 | } // namespace core |
| 368 | } // namespace mojo |
| 369 | |
| 370 | #endif // MOJO_CORE_CHANNEL_H_ |