root/mojo/system/message_in_transit.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


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

#ifndef MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_
#define MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_

#include <stdint.h>

#include <vector>

#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "mojo/embedder/platform_handle.h"
#include "mojo/system/dispatcher.h"
#include "mojo/system/system_impl_export.h"

namespace mojo {
namespace system {

class Channel;

// This class is used to represent data in transit. It is thread-unsafe.
//
// |MessageInTransit| buffers:
//
// A |MessageInTransit| can be serialized by writing the main buffer and then,
// if it has one, the secondary buffer. Both buffers are
// |kMessageAlignment|-byte aligned and a multiple of |kMessageAlignment| bytes
// in size.
//
// The main buffer consists of the header (of type |Header|, which is an
// internal detail of this class) followed immediately by the message data
// (accessed by |bytes()| and of size |num_bytes()|, and also
// |kMessageAlignment|-byte aligned), and then any padding needed to make the
// main buffer a multiple of |kMessageAlignment| bytes in size.
//
// The secondary buffer consists first of a table of |HandleTableEntry|s (each
// of which is already a multiple of |kMessageAlignment| in size), followed by
// data needed for the |HandleTableEntry|s: A |HandleTableEntry| consists of an
// offset (in bytes, relative to the start of the secondary buffer; we guarantee
// that it's a multiple of |kMessageAlignment|), and a size (in bytes).
class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit {
 public:
  typedef uint16_t Type;
  // Messages that are forwarded to |MessagePipeEndpoint|s.
  static const Type kTypeMessagePipeEndpoint = 0;
  // Messages that are forwarded to |MessagePipe|s.
  static const Type kTypeMessagePipe = 1;
  // Messages that are consumed by the channel.
  static const Type kTypeChannel = 2;

  typedef uint16_t Subtype;
  // Subtypes for type |kTypeMessagePipeEndpoint|:
  static const Subtype kSubtypeMessagePipeEndpointData = 0;
  // Subtypes for type |kTypeMessagePipe|:
  static const Subtype kSubtypeMessagePipePeerClosed = 0;
  // Subtypes for type |kTypeChannel|:
  static const Subtype kSubtypeChannelRunMessagePipeEndpoint = 0;

  typedef uint32_t EndpointId;
  // Never a valid endpoint ID.
  static const EndpointId kInvalidEndpointId = 0;

  // Messages (the header and data) must always be aligned to a multiple of this
  // quantity (which must be a power of 2).
  static const size_t kMessageAlignment = 8;

  // The maximum size of a single serialized dispatcher. This must be a multiple
  // of |kMessageAlignment|.
  static const size_t kMaxSerializedDispatcherSize = 10000;

  // Forward-declare |Header| so that |View| can use it:
 private:
  struct Header;
 public:
  // This represents a view of serialized message data in a raw buffer.
  class MOJO_SYSTEM_IMPL_EXPORT View {
   public:
    // Constructs a view from the given buffer of the given size. (The size must
    // be as provided by |MessageInTransit::GetNextMessageSize()|.) The buffer
    // must remain alive/unmodified through the lifetime of this object.
    // |buffer| should be |kMessageAlignment|-byte aligned.
    View(size_t message_size, const void* buffer);

    // Checks the following things versus pre-determined limits:
    //   - |num_bytes()| and |main_buffer_size()|,
    //   - |num_handles()| and |secondary_buffer_size()|,
    //   - the entries in the handle entry table (that the sizes and offsets are
    //     valid).
    // Note: It does not check the serialized dispatcher data itself.
    //
    // It returns true (and leaves |error_message| alone) if this object appears
    // to be a valid message (according to the above) and false, pointing
    // |*error_message| to a suitable error message, if not.
    bool IsValid(const char** error_message) const;

    // API parallel to that for |MessageInTransit| itself (mostly getters for
    // header data).
    const void* main_buffer() const { return buffer_; }
    size_t main_buffer_size() const {
      return RoundUpMessageAlignment(sizeof(Header) + header()->num_bytes);
    }
    const void* secondary_buffer() const {
      return (total_size() > main_buffer_size()) ?
          static_cast<const char*>(buffer_) + main_buffer_size() : NULL;
    }
    size_t secondary_buffer_size() const {
      return total_size() - main_buffer_size();
    }
    size_t total_size() const { return header()->total_size; }
    uint32_t num_bytes() const { return header()->num_bytes; }
    const void* bytes() const {
      return static_cast<const char*>(buffer_) + sizeof(Header);
    }
    uint32_t num_handles() const { return header()->num_handles; }
    Type type() const { return header()->type; }
    Subtype subtype() const { return header()->subtype; }
    EndpointId source_id() const { return header()->source_id; }
    EndpointId destination_id() const { return header()->destination_id; }

   private:
    const Header* header() const { return static_cast<const Header*>(buffer_); }

    const void* const buffer_;

    // Though this struct is trivial, disallow copy and assign, since it doesn't
    // own its data. (If you're copying/assigning this, you're probably doing
    // something wrong.)
    DISALLOW_COPY_AND_ASSIGN(View);
  };

  // |bytes| is optional; if null, the message data will be zero-initialized.
  MessageInTransit(Type type,
                   Subtype subtype,
                   uint32_t num_bytes,
                   uint32_t num_handles,
                   const void* bytes);
  // Constructs a |MessageInTransit| from a |View|.
  explicit MessageInTransit(const View& message_view);

  ~MessageInTransit();

  // Gets the size of the next message from |buffer|, which has |buffer_size|
  // bytes currently available, returning true and setting |*next_message_size|
  // on success. |buffer| should be aligned on a |kMessageAlignment| boundary
  // (and on success, |*next_message_size| will be a multiple of
  // |kMessageAlignment|).
  // TODO(vtl): In |RawChannelPosix|, the alignment requirements are currently
  // satisified on a faith-based basis.
  static bool GetNextMessageSize(const void* buffer,
                                 size_t buffer_size,
                                 size_t* next_message_size);

  // Makes this message "own" the given set of dispatchers. The dispatchers must
  // not be referenced from anywhere else (in particular, not from the handle
  // table), i.e., each dispatcher must have a reference count of 1. This
  // message must not already have dispatchers.
  void SetDispatchers(
      scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > dispatchers);

  // Serializes any dispatchers to the secondary buffer. This message must not
  // already have a secondary buffer (so this must only be called once). The
  // caller must ensure (e.g., by holding on to a reference) that |channel|
  // stays alive through the call.
  void SerializeAndCloseDispatchers(Channel* channel);

  // Deserializes any dispatchers from the secondary buffer. This message must
  // not have any dispatchers attached.
  // TODO(vtl): Having to copy the secondary buffer (in the constructor from a
  // |View|) is suboptimal. Maybe this should just be done in the constructor?
  void DeserializeDispatchers(Channel* channel);

  // Gets the main buffer and its size (in number of bytes), respectively.
  const void* main_buffer() const { return main_buffer_; }
  size_t main_buffer_size() const { return main_buffer_size_; }

  // Gets the secondary buffer and its size (in number of bytes), respectively.
  const void* secondary_buffer() const { return secondary_buffer_; }
  size_t secondary_buffer_size() const { return secondary_buffer_size_; }

  // Gets the total size of the message (see comment in |Header|, below).
  size_t total_size() const { return header()->total_size; }

  // Gets the size of the message data.
  uint32_t num_bytes() const { return header()->num_bytes; }

  // Gets the message data (of size |num_bytes()| bytes).
  const void* bytes() const {
    return static_cast<const char*>(main_buffer_) + sizeof(Header);
  }
  void* bytes() { return static_cast<char*>(main_buffer_) + sizeof(Header); }

  uint32_t num_handles() const { return header()->num_handles; }

  Type type() const { return header()->type; }
  Subtype subtype() const { return header()->subtype; }
  EndpointId source_id() const { return header()->source_id; }
  EndpointId destination_id() const { return header()->destination_id; }

  void set_source_id(EndpointId source_id) { header()->source_id = source_id; }
  void set_destination_id(EndpointId destination_id) {
    header()->destination_id = destination_id;
  }

  // Gets the dispatchers attached to this message; this may return null if
  // there are none. Note that the caller may mutate the set of dispatchers
  // (e.g., take ownership of all the dispatchers, leaving the vector empty).
  std::vector<scoped_refptr<Dispatcher> >* dispatchers() {
    return dispatchers_.get();
  }

  // Returns true if this message has dispatchers attached.
  bool has_dispatchers() const {
    return dispatchers_ && !dispatchers_->empty();
  }

  // Gets the platform-specific handles attached to this message; this may
  // return null if there are none. Note that the caller may mutate the set of
  // platform-specific handles.
  std::vector<embedder::PlatformHandle>* platform_handles() {
    return platform_handles_.get();
  }

  // Returns true if this message has platform-specific handles attached.
  bool has_platform_handles() const {
    return platform_handles_ && !platform_handles_->empty();
  }

  // Rounds |n| up to a multiple of |kMessageAlignment|.
  static inline size_t RoundUpMessageAlignment(size_t n) {
    return (n + kMessageAlignment - 1) & ~(kMessageAlignment - 1);
  }

 private:
  // To allow us to make assertions about |Header| in the .cc file.
  struct PrivateStructForCompileAsserts;

  // "Header" for the data. Must be a multiple of |kMessageAlignment| bytes in
  // size. Must be POD.
  struct Header {
    // Total size of the message, including the header, the message data
    // ("bytes") including padding (to make it a multiple of |kMessageAlignment|
    // bytes), and serialized handle information. Note that this may not be the
    // correct value if dispatchers are attached but
    // |SerializeAndCloseDispatchers()| has not been called.
    uint32_t total_size;
    Type type;  // 2 bytes.
    Subtype subtype;  // 2 bytes.
    EndpointId source_id;  // 4 bytes.
    EndpointId destination_id;  // 4 bytes.
    // Size of actual message data.
    uint32_t num_bytes;
    // Number of handles "attached".
    uint32_t num_handles;
  };

  struct HandleTableEntry {
    int32_t type;  // From |Dispatcher::Type| (|kTypeUnknown| for "invalid").
    uint32_t offset;  // Relative to the start of the secondary buffer.
    uint32_t size;  // (Not including any padding.)
    uint32_t unused;
  };

  // The maximum possible size of a valid secondary buffer: for each handle,
  // there'll be a handle table entry and its serialized data.
  static const size_t kMaxSecondaryBufferSize;

  // Validates the secondary buffer. Returns null on success, or a
  // human-readable error message on error.
  static const char* ValidateSecondaryBuffer(size_t num_handles,
                                             const void* secondary_buffer,
                                             size_t secondary_buffer_size);

  const Header* header() const {
    return static_cast<const Header*>(main_buffer_);
  }
  Header* header() { return static_cast<Header*>(main_buffer_); }

  void UpdateTotalSize();

  size_t main_buffer_size_;
  void* main_buffer_;

  size_t secondary_buffer_size_;
  void* secondary_buffer_;  // May be null.

  // Any dispatchers that may be attached to this message. These dispatchers
  // should be "owned" by this message, i.e., have a ref count of exactly 1. (We
  // allow a dispatcher entry to be null, in case it couldn't be duplicated for
  // some reason.)
  scoped_ptr<std::vector<scoped_refptr<Dispatcher> > > dispatchers_;

  // Any platform-specific handles attached to this message (for inter-process
  // transport). The vector (if any) owns the handles that it contains (and is
  // responsible for closing them).
  // TODO(vtl): With C++11, change it to a vector of |ScopedPlatformHandles|.
  scoped_ptr<std::vector<embedder::PlatformHandle> > platform_handles_;

  DISALLOW_COPY_AND_ASSIGN(MessageInTransit);
};

}  // namespace system
}  // namespace mojo

#endif  // MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_

/* [<][>][^][v][top][bottom][index][help] */