Home | History | Annotate | Download | only in system
      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_EDK_SYSTEM_CHANNEL_H_
      6 #define MOJO_EDK_SYSTEM_CHANNEL_H_
      7 
      8 #include "base/logging.h"
      9 #include "base/macros.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/process/process_handle.h"
     12 #include "base/task_runner.h"
     13 #include "mojo/edk/embedder/connection_params.h"
     14 #include "mojo/edk/embedder/platform_handle_vector.h"
     15 #include "mojo/edk/embedder/scoped_platform_handle.h"
     16 
     17 namespace mojo {
     18 namespace edk {
     19 
     20 const size_t kChannelMessageAlignment = 8;
     21 
     22 constexpr bool IsAlignedForChannelMessage(size_t n) {
     23   return n % kChannelMessageAlignment == 0;
     24 }
     25 
     26 // Channel provides a thread-safe interface to read and write arbitrary
     27 // delimited messages over an underlying I/O channel, optionally transferring
     28 // one or more platform handles in the process.
     29 class MOJO_SYSTEM_IMPL_EXPORT Channel
     30     : public base::RefCountedThreadSafe<Channel> {
     31  public:
     32   struct Message;
     33 
     34   using MessagePtr = std::unique_ptr<Message>;
     35 
     36   // A message to be written to a channel.
     37   struct MOJO_SYSTEM_IMPL_EXPORT Message {
     38     enum class MessageType : uint16_t {
     39       // An old format normal message, that uses the LegacyHeader.
     40       // Only used on Android and ChromeOS.
     41       // TODO(jcivelli): remove legacy support when Arc++ has updated to Mojo
     42       //                 with normal versioned messages. crbug.com/695645
     43       NORMAL_LEGACY = 0,
     44 #if defined(OS_MACOSX)
     45       // A control message containing handles to echo back.
     46       HANDLES_SENT,
     47       // A control message containing handles that can now be closed.
     48       HANDLES_SENT_ACK,
     49 #endif
     50       // A normal message that uses Header and can contain extra header values.
     51       NORMAL,
     52     };
     53 
     54 #pragma pack(push, 1)
     55     // Old message wire format for ChromeOS and Android, used by NORMAL_LEGACY
     56     // messages.
     57     struct LegacyHeader {
     58       // Message size in bytes, including the header.
     59       uint32_t num_bytes;
     60 
     61       // Number of attached handles.
     62       uint16_t num_handles;
     63 
     64       MessageType message_type;
     65     };
     66 
     67     // Header used by NORMAL messages.
     68     // To preserve backward compatibility with LegacyHeader, the num_bytes and
     69     // message_type field must be at the same offset as in LegacyHeader.
     70     struct Header {
     71       // Message size in bytes, including the header.
     72       uint32_t num_bytes;
     73 
     74       // Total size of header, including extra header data (i.e. HANDLEs on
     75       // windows).
     76       uint16_t num_header_bytes;
     77 
     78       MessageType message_type;
     79 
     80       // Number of attached handles. May be less than the reserved handle
     81       // storage size in this message on platforms that serialise handles as
     82       // data (i.e. HANDLEs on Windows, Mach ports on OSX).
     83       uint16_t num_handles;
     84 
     85       char padding[6];
     86     };
     87 
     88 #if defined(OS_MACOSX) && !defined(OS_IOS)
     89     struct MachPortsEntry {
     90       // Index of Mach port in the original vector of PlatformHandles.
     91       uint16_t index;
     92 
     93       // Mach port name.
     94       uint32_t mach_port;
     95       static_assert(sizeof(mach_port_t) <= sizeof(uint32_t),
     96                     "mach_port_t must be no larger than uint32_t");
     97     };
     98     static_assert(sizeof(MachPortsEntry) == 6,
     99                   "sizeof(MachPortsEntry) must be 6 bytes");
    100 
    101     // Structure of the extra header field when present on OSX.
    102     struct MachPortsExtraHeader {
    103       // Actual number of Mach ports encoded in the extra header.
    104       uint16_t num_ports;
    105 
    106       // Array of encoded Mach ports. If |num_ports| > 0, |entries[0]| through
    107       // to |entries[num_ports-1]| inclusive are valid.
    108       MachPortsEntry entries[0];
    109     };
    110     static_assert(sizeof(MachPortsExtraHeader) == 2,
    111                   "sizeof(MachPortsExtraHeader) must be 2 bytes");
    112 #elif defined(OS_WIN)
    113     struct HandleEntry {
    114       // The windows HANDLE. HANDLEs are guaranteed to fit inside 32-bits.
    115       // See: https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx
    116       uint32_t handle;
    117     };
    118     static_assert(sizeof(HandleEntry) == 4,
    119                   "sizeof(HandleEntry) must be 4 bytes");
    120 #endif
    121 #pragma pack(pop)
    122 
    123     // Allocates and owns a buffer for message data with enough capacity for
    124     // |payload_size| bytes plus a header, plus |max_handles| platform handles.
    125     Message(size_t payload_size, size_t max_handles);
    126     Message(size_t payload_size, size_t max_handles, MessageType message_type);
    127     ~Message();
    128 
    129     // Constructs a Message from serialized message data.
    130     static MessagePtr Deserialize(const void* data, size_t data_num_bytes);
    131 
    132     const void* data() const { return data_; }
    133     size_t data_num_bytes() const { return size_; }
    134 
    135     const void* extra_header() const;
    136     void* mutable_extra_header();
    137     size_t extra_header_size() const;
    138 
    139     void* mutable_payload();
    140     const void* payload() const;
    141     size_t payload_size() const;
    142 
    143     size_t num_handles() const;
    144     bool has_handles() const;
    145 #if defined(OS_MACOSX) && !defined(OS_IOS)
    146     bool has_mach_ports() const;
    147 #endif
    148 
    149     bool is_legacy_message() const;
    150     LegacyHeader* legacy_header() const;
    151     Header* header() const;
    152 
    153     // Note: SetHandles() and TakeHandles() invalidate any previous value of
    154     // handles().
    155     void SetHandles(ScopedPlatformHandleVectorPtr new_handles);
    156     ScopedPlatformHandleVectorPtr TakeHandles();
    157     // Version of TakeHandles that returns a vector of platform handles suitable
    158     // for transfer over an underlying OS mechanism. i.e. file descriptors over
    159     // a unix domain socket. Any handle that cannot be transferred this way,
    160     // such as Mach ports, will be removed.
    161     ScopedPlatformHandleVectorPtr TakeHandlesForTransport();
    162 
    163 #if defined(OS_WIN)
    164     // Prepares the handles in this message for use in a different process.
    165     // Upon calling this the handles should belong to |from_process|; after the
    166     // call they'll belong to |to_process|. The source handles are always
    167     // closed by this call. Returns false iff one or more handles failed
    168     // duplication.
    169     static bool RewriteHandles(base::ProcessHandle from_process,
    170                                base::ProcessHandle to_process,
    171                                PlatformHandleVector* handles);
    172 #endif
    173 
    174     void SetVersionForTest(uint16_t version_number);
    175 
    176    private:
    177     size_t size_ = 0;
    178     size_t max_handles_ = 0;
    179     char* data_ = nullptr;
    180 
    181     ScopedPlatformHandleVectorPtr handle_vector_;
    182 
    183 #if defined(OS_WIN)
    184     // On Windows, handles are serialised into the extra header section.
    185     HandleEntry* handles_ = nullptr;
    186 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    187     // On OSX, handles are serialised into the extra header section.
    188     MachPortsExtraHeader* mach_ports_header_ = nullptr;
    189 #endif
    190 
    191     DISALLOW_COPY_AND_ASSIGN(Message);
    192   };
    193 
    194   // Delegate methods are called from the I/O task runner with which the Channel
    195   // was created (see Channel::Create).
    196   class Delegate {
    197    public:
    198     virtual ~Delegate() {}
    199 
    200     // Notify of a received message. |payload| is not owned and must not be
    201     // retained; it will be null if |payload_size| is 0. |handles| are
    202     // transferred to the callee.
    203     virtual void OnChannelMessage(const void* payload,
    204                                   size_t payload_size,
    205                                   ScopedPlatformHandleVectorPtr handles) = 0;
    206 
    207     // Notify that an error has occured and the Channel will cease operation.
    208     virtual void OnChannelError() = 0;
    209   };
    210 
    211   // Creates a new Channel around a |platform_handle|, taking ownership of the
    212   // handle. All I/O on the handle will be performed on |io_task_runner|.
    213   // Note that ShutDown() MUST be called on the Channel some time before
    214   // |delegate| is destroyed.
    215   static scoped_refptr<Channel> Create(
    216       Delegate* delegate,
    217       ConnectionParams connection_params,
    218       scoped_refptr<base::TaskRunner> io_task_runner);
    219 
    220   // Request that the channel be shut down. This should always be called before
    221   // releasing the last reference to a Channel to ensure that it's cleaned up
    222   // on its I/O task runner's thread.
    223   //
    224   // Delegate methods will no longer be invoked after this call.
    225   void ShutDown();
    226 
    227   // Begin processing I/O events. Delegate methods must only be invoked after
    228   // this call.
    229   virtual void Start() = 0;
    230 
    231   // Stop processing I/O events.
    232   virtual void ShutDownImpl() = 0;
    233 
    234   // Queues an outgoing message on the Channel. This message will either
    235   // eventually be written or will fail to write and trigger
    236   // Delegate::OnChannelError.
    237   virtual void Write(MessagePtr message) = 0;
    238 
    239   // Causes the platform handle to leak when this channel is shut down instead
    240   // of closing it.
    241   virtual void LeakHandle() = 0;
    242 
    243  protected:
    244   explicit Channel(Delegate* delegate);
    245   virtual ~Channel();
    246 
    247   // Called by the implementation when it wants somewhere to stick data.
    248   // |*buffer_capacity| may be set by the caller to indicate the desired buffer
    249   // size. If 0, a sane default size will be used instead.
    250   //
    251   // Returns the address of a buffer which can be written to, and indicates its
    252   // actual capacity in |*buffer_capacity|.
    253   char* GetReadBuffer(size_t* buffer_capacity);
    254 
    255   // Called by the implementation when new data is available in the read
    256   // buffer. Returns false to indicate an error. Upon success,
    257   // |*next_read_size_hint| will be set to a recommended size for the next
    258   // read done by the implementation.
    259   bool OnReadComplete(size_t bytes_read, size_t* next_read_size_hint);
    260 
    261   // Called by the implementation when something goes horribly wrong. It is NOT
    262   // OK to call this synchronously from any public interface methods.
    263   void OnError();
    264 
    265   // Retrieves the set of platform handles read for a given message.
    266   // |extra_header| and |extra_header_size| correspond to the extra header data.
    267   // Depending on the Channel implementation, this body may encode platform
    268   // handles, or handles may be stored and managed elsewhere by the
    269   // implementation.
    270   //
    271   // Returns |false| on unrecoverable error (i.e. the Channel should be closed).
    272   // Returns |true| otherwise. Note that it is possible on some platforms for an
    273   // insufficient number of handles to be available when this call is made, but
    274   // this is not necessarily an error condition. In such cases this returns
    275   // |true| but |*handles| will also be reset to null.
    276   virtual bool GetReadPlatformHandles(
    277       size_t num_handles,
    278       const void* extra_header,
    279       size_t extra_header_size,
    280       ScopedPlatformHandleVectorPtr* handles) = 0;
    281 
    282   // Handles a received control message. Returns |true| if the message is
    283   // accepted, or |false| otherwise.
    284   virtual bool OnControlMessage(Message::MessageType message_type,
    285                                 const void* payload,
    286                                 size_t payload_size,
    287                                 ScopedPlatformHandleVectorPtr handles);
    288 
    289  private:
    290   friend class base::RefCountedThreadSafe<Channel>;
    291 
    292   class ReadBuffer;
    293 
    294   Delegate* delegate_;
    295   const std::unique_ptr<ReadBuffer> read_buffer_;
    296 
    297   DISALLOW_COPY_AND_ASSIGN(Channel);
    298 };
    299 
    300 }  // namespace edk
    301 }  // namespace mojo
    302 
    303 #endif  // MOJO_EDK_SYSTEM_CHANNEL_H_
    304