summaryrefslogtreecommitdiffstats
path: root/mojo/system/message_in_transit.h
blob: 0cec0ae20cd6d3fca0a8f0bdcef84f585907ddfd (plain)
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
// 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 "base/macros.h"
#include "mojo/system/system_impl_export.h"

namespace mojo {
namespace system {

// This class is used to represent data in transit. It is thread-unsafe.
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;

  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;

  enum OwnedBuffer { OWNED_BUFFER };
  // Constructor for a |MessageInTransit| that owns its buffer. |bytes| is
  // optional; if null, the message data will be zero-initialized.
  MessageInTransit(OwnedBuffer,
                   Type type,
                   Subtype subtype,
                   uint32_t num_bytes,
                   uint32_t num_handles,
                   const void* bytes);
  // "Copy" constructor. The input |MessageInTransit| may own its buffer or not.
  // The constructed |MessageInTransit| will own its buffer.
  MessageInTransit(OwnedBuffer,
                   const MessageInTransit& other);

  enum UnownedBuffer { UNOWNED_BUFFER };
  // Constructor for a |MessageInTransit| that is a "view" into another buffer.
  // |buffer| should point to a fully-serialized |MessageInTransit|, and should
  // be aligned on a |kMessageAlignment|-byte boundary. |message_size| should be
  // the value provided by |GetNextMessageSize()|, and |buffer| should have at
  // least that many bytes available. |buffer| should live (without change to
  // the first |message_size| bytes) at least as long the new |MessageInTransit|
  // does.
  //
  // Note: You probably don't want to heap-allocate this kind of
  // |MessageInTransit| (and, e.g., put it into a |scoped_ptr|); you definitely
  // don't want to pass it as a parameter in a |scoped_ptr|. Whenever you use
  // this, you can probably create it directly on the stack.
  MessageInTransit(UnownedBuffer, size_t message_size, void* buffer);
  ~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);

  // Gets the "main" buffer for a |MessageInTransit|. A |MessageInTransit| can
  // be serialized by writing the main buffer. The returned pointer will be
  // aligned to a multiple of |kMessageAlignment| bytes, and the size of the
  // buffer (see below) will also be a multiple of |kMessageAlignment|.
  //
  // The main buffer always consists of the header (of type |Header|, which is
  // an internal detail), followed by the message data, accessed by |bytes()|
  // (of size |num_bytes()|, and also |kMessageAlignment|-aligned), and then any
  // necessary padding to make |main_buffer_size()| a multiple of
  // |kMessageAlignment|.
  // TODO(vtl): Add a "secondary" buffer, so that this makes more sense.
  const void* main_buffer() const { return main_buffer_; }

  // Gets the size of the main buffer (in number of bytes).
  size_t main_buffer_size() const { return main_buffer_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;
  }

  // TODO(vtl): Add whatever's necessary to transport handles.

  // 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 data following the "header".
    uint32_t data_size;
    Type type;
    Subtype subtype;
    EndpointId source_id;
    EndpointId destination_id;
    // Size of actual message data.
    uint32_t num_bytes;
    // Number of handles "attached".
    uint32_t num_handles;
    // To be used soon.
    uint32_t reserved0;
    uint32_t reserved1;
  };

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

  bool owns_main_buffer_;
  size_t main_buffer_size_;
  void* main_buffer_;

  DISALLOW_COPY_AND_ASSIGN(MessageInTransit);
};

}  // namespace system
}  // namespace mojo

#endif  // MOJO_SYSTEM_MESSAGE_IN_TRANSIT_H_