summaryrefslogtreecommitdiffstats
path: root/mojo/edk/system/transport_data.h
blob: d54ad2ab2b19486e82aa98f241867ebbc9b3f9d2 (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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2014 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_EDK_SYSTEM_TRANSPORT_DATA_H_
#define MOJO_EDK_SYSTEM_TRANSPORT_DATA_H_

#include <stdint.h>

#include <vector>

#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "mojo/edk/embedder/platform_handle.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/system/dispatcher.h"
#include "mojo/edk/system/system_impl_export.h"

namespace mojo {
namespace system {

class Channel;

// This class is used by |MessageInTransit| to represent handles (|Dispatcher|s)
// in various stages of serialization.
//
// The stages are:
//   - Before reaching |TransportData|: Turn |DispatcherTransport|s into
//     |Dispatcher|s that are "owned" by (and attached to) a |MessageInTransit|.
//     This invalidates the handles in the space of the sending application
//     (and, e.g., if another thread is waiting on such a handle, it'll be
//     notified of this invalidation).
//   - Serialize these dispatchers into the |TransportData|: First, for each
//     attached dispatcher, there's an entry in the |TransportData|'s "handle
//     table", which points to a segment of (dispatcher-type-dependent) data.
//   - During the serialization of the dispatchers, |PlatformHandle|s may be
//     detached from the dispatchers and attached to the |TransportData|.
//   - Before sending the |MessageInTransit|, including its main buffer and the
//     |TransportData|'s buffer, the |Channel| sends any |PlatformHandle|s (in a
//     platform-, and possibly sandbox-situation-, specific way) first. In doing
//     so, it appends a "platform handle table" to the |TransportData|
//     containing information about how to deserialize these |PlatformHandle|s.
//   - Finally, at this point, to send the |MessageInTransit|, there only
//     remains "inert" data: the |MessageInTransit|'s main buffer and data from
//     the |TransportData|, consisting of the "handle table" (one entry for each
//     attached dispatcher), dispatcher-type-specific data (one segment for each
//     entry in the "handle table"), and the "platform handle table" (one entry
//     for each attached |PlatformHandle|).
//
// To receive a message (|MessageInTransit|), the "reverse" happens:
//   - On POSIX, receive and buffer |PlatformHandle|s (i.e., FDs), which were
//     sent before the "inert" data.
//   - Receive the "inert" data from the |MessageInTransit|. Examine its
//     "platform handle table". On POSIX, match its entries with the buffered
//     |PlatformHandle|s, which were previously received. On Windows, do what's
//     necessary to obtain |PlatformHandle|s (e.g.: i. if the sender is fully
//     trusted and able to duplicate handle into the receiver, then just pick
//     out the |HANDLE| value; ii. if the receiver is fully trusted and able to
//     duplicate handles from the receiver, do the |DuplicateHandle()|; iii.
//     otherwise, talk to a broker to get handles). Reattach all the
//     |PlatformHandle|s to the |MessageInTransit|.
//   - For each entry in the "handle table", use serialized dispatcher data to
//     reconstitute a dispatcher, taking ownership of associated
//     |PlatformHandle|s (and detaching them). Attach these dispatchers to the
//     |MessageInTransit|.
//   - At this point, the |MessageInTransit| consists of its main buffer
//     (primarily the data payload) and the attached dispatchers; the
//     |TransportData| can be discarded.
//   - When |MojoReadMessage()| is to give data to the application, attach the
//     dispatchers to the (global, "core") handle table, getting handles; give
//     the application the data payload and these handles.
//
// TODO(vtl): Everything above involving |PlatformHandle|s.
class MOJO_SYSTEM_IMPL_EXPORT TransportData {
 public:
  // The maximum size of a single serialized dispatcher. This must be a multiple
  // of |kMessageAlignment|.
  static const size_t kMaxSerializedDispatcherSize = 10000;

  // The maximum number of platform handles to attach for a single serialized
  // dispatcher.
  static const size_t kMaxSerializedDispatcherPlatformHandles = 2;

  // The maximum possible size of a valid transport data buffer.
  static size_t GetMaxBufferSize();

  // The maximum total number of platform handles that may be attached.
  static size_t GetMaxPlatformHandles();

  TransportData(scoped_ptr<DispatcherVector> dispatchers, Channel* channel);

#if defined(OS_POSIX)
  // This is a hacky POSIX-only constructor to directly attach only platform
  // handles to a message, used by |RawChannelPosix| to split messages with too
  // many platform handles into multiple messages. |Header| will be present, but
  // be zero. (No other information will be attached, and
  // |RawChannel::GetSerializedPlatformHandleSize()| should return zero.)
  explicit TransportData(
      embedder::ScopedPlatformHandleVectorPtr platform_handles);
#endif

  ~TransportData();

  const void* buffer() const { return buffer_.get(); }
  void* buffer() { return buffer_.get(); }
  size_t buffer_size() const { return buffer_size_; }

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

  // Gets attached platform-specific handles; this may return null if there are
  // none. Note that the caller may mutate the set of platform-specific handles.
  const embedder::PlatformHandleVector* platform_handles() const {
    return platform_handles_.get();
  }
  embedder::PlatformHandleVector* platform_handles() {
    return platform_handles_.get();
  }

  // Receive-side functions:

  // Checks if the given buffer (from the "wire") looks like a valid
  // |TransportData| buffer. (Should only be called if |buffer_size| is
  // nonzero.) Returns null if valid, and a pointer to a human-readable error
  // message (for debug/logging purposes) on error. Note: This checks the
  // validity of the handle table entries (i.e., does range checking), but does
  // not check that the validity of the actual serialized dispatcher
  // information.
  static const char* ValidateBuffer(size_t serialized_platform_handle_size,
                                    const void* buffer,
                                    size_t buffer_size);

  // Gets the platform handle table from a (valid) |TransportData| buffer (which
  // should have been validated using |ValidateBuffer()| first).
  static void GetPlatformHandleTable(const void* transport_data_buffer,
                                     size_t* num_platform_handles,
                                     const void** platform_handle_table);

  // Deserializes dispatchers from the given (serialized) transport data buffer
  // (typically from a |MessageInTransit::View|) and vector of platform handles.
  // |buffer| should be non-null and |buffer_size| should be nonzero.
  static scoped_ptr<DispatcherVector> DeserializeDispatchers(
      const void* buffer,
      size_t buffer_size,
      embedder::ScopedPlatformHandleVectorPtr platform_handles,
      Channel* channel);

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

  // Header for the "secondary buffer"/"transport data". Must be a multiple of
  // |MessageInTransit::kMessageAlignment| in size. Must be POD.
  struct Header {
    uint32_t num_handles;
    // TODO(vtl): Not used yet:
    uint32_t platform_handle_table_offset;
    uint32_t num_platform_handles;
    uint32_t unused;
  };

  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;
  };

  const Header* header() const {
    return reinterpret_cast<const Header*>(buffer_.get());
  }

  size_t buffer_size_;
  scoped_ptr<char, base::AlignedFreeDeleter> buffer_;  // Never null.

  // 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|.
  embedder::ScopedPlatformHandleVectorPtr platform_handles_;

  DISALLOW_COPY_AND_ASSIGN(TransportData);
};

}  // namespace system
}  // namespace mojo

#endif  // MOJO_EDK_SYSTEM_TRANSPORT_DATA_H_