1// Copyright 2014 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_SYSTEM_TRANSPORT_DATA_H_
6#define MOJO_SYSTEM_TRANSPORT_DATA_H_
7
8#include <stdint.h>
9
10#include <vector>
11
12#include "base/macros.h"
13#include "base/memory/aligned_memory.h"
14#include "base/memory/scoped_ptr.h"
15#include "build/build_config.h"
16#include "mojo/embedder/platform_handle.h"
17#include "mojo/embedder/platform_handle_vector.h"
18#include "mojo/system/dispatcher.h"
19#include "mojo/system/system_impl_export.h"
20
21namespace mojo {
22namespace system {
23
24class Channel;
25
26// This class is used by |MessageInTransit| to represent handles (|Dispatcher|s)
27// in various stages of serialization.
28//
29// The stages are:
30//   - Before reaching |TransportData|: Turn |DispatcherTransport|s into
31//     |Dispatcher|s that are "owned" by (and attached to) a |MessageInTransit|.
32//     This invalidates the handles in the space of the sending application
33//     (and, e.g., if another thread is waiting on such a handle, it'll be
34//     notified of this invalidation).
35//   - Serialize these dispatchers into the |TransportData|: First, for each
36//     attached dispatcher, there's an entry in the |TransportData|'s "handle
37//     table", which points to a segment of (dispatcher-type-dependent) data.
38//   - During the serialization of the dispatchers, |PlatformHandle|s may be
39//     detached from the dispatchers and attached to the |TransportData|.
40//   - Before sending the |MessageInTransit|, including its main buffer and the
41//     |TransportData|'s buffer, the |Channel| sends any |PlatformHandle|s (in a
42//     platform-, and possibly sandbox-situation-, specific way) first. In doing
43//     so, it appends a "platform handle table" to the |TransportData|
44//     containing information about how to deserialize these |PlatformHandle|s.
45//   - Finally, at this point, to send the |MessageInTransit|, there only
46//     remains "inert" data: the |MessageInTransit|'s main buffer and data from
47//     the |TransportData|, consisting of the "handle table" (one entry for each
48//     attached dispatcher), dispatcher-type-specific data (one segment for each
49//     entry in the "handle table"), and the "platform handle table" (one entry
50//     for each attached |PlatformHandle|).
51//
52// To receive a message (|MessageInTransit|), the "reverse" happens:
53//   - On POSIX, receive and buffer |PlatformHandle|s (i.e., FDs), which were
54//     sent before the "inert" data.
55//   - Receive the "inert" data from the |MessageInTransit|. Examine its
56//     "platform handle table". On POSIX, match its entries with the buffered
57//     |PlatformHandle|s, which were previously received. On Windows, do what's
58//     necessary to obtain |PlatformHandle|s (e.g.: i. if the sender is fully
59//     trusted and able to duplicate handle into the receiver, then just pick
60//     out the |HANDLE| value; ii. if the receiver is fully trusted and able to
61//     duplicate handles from the receiver, do the |DuplicateHandle()|; iii.
62//     otherwise, talk to a broker to get handles). Reattach all the
63//     |PlatformHandle|s to the |MessageInTransit|.
64//   - For each entry in the "handle table", use serialized dispatcher data to
65//     reconstitute a dispatcher, taking ownership of associated
66//     |PlatformHandle|s (and detaching them). Attach these dispatchers to the
67//     |MessageInTransit|.
68//   - At this point, the |MessageInTransit| consists of its main buffer
69//     (primarily the data payload) and the attached dispatchers; the
70//     |TransportData| can be discarded.
71//   - When |MojoReadMessage()| is to give data to the application, attach the
72//     dispatchers to the (global, "core") handle table, getting handles; give
73//     the application the data payload and these handles.
74//
75// TODO(vtl): Everything above involving |PlatformHandle|s.
76class MOJO_SYSTEM_IMPL_EXPORT TransportData {
77 public:
78  // The maximum size of a single serialized dispatcher. This must be a multiple
79  // of |kMessageAlignment|.
80  static const size_t kMaxSerializedDispatcherSize = 10000;
81
82  // The maximum number of platform handles to attach for a single serialized
83  // dispatcher.
84  static const size_t kMaxSerializedDispatcherPlatformHandles = 2;
85
86  // The maximum possible size of a valid transport data buffer.
87  static const size_t kMaxBufferSize;
88
89  // The maximum total number of platform handles that may be attached.
90  static const size_t kMaxPlatformHandles;
91
92  TransportData(scoped_ptr<DispatcherVector> dispatchers, Channel* channel);
93
94#if defined(OS_POSIX)
95  // This is a hacky POSIX-only constructor to directly attach only platform
96  // handles to a message, used by |RawChannelPosix| to split messages with too
97  // many platform handles into multiple messages. |Header| will be present, but
98  // be zero. (No other information will be attached, and
99  // |RawChannel::GetSerializedPlatformHandleSize()| should return zero.)
100  explicit TransportData(
101      embedder::ScopedPlatformHandleVectorPtr platform_handles);
102#endif
103
104  ~TransportData();
105
106  const void* buffer() const { return buffer_.get(); }
107  void* buffer() { return buffer_.get(); }
108  size_t buffer_size() const { return buffer_size_; }
109
110  uint32_t platform_handle_table_offset() const {
111    return header()->platform_handle_table_offset;
112  }
113
114  // Gets attached platform-specific handles; this may return null if there are
115  // none. Note that the caller may mutate the set of platform-specific handles.
116  const embedder::PlatformHandleVector* platform_handles() const {
117    return platform_handles_.get();
118  }
119  embedder::PlatformHandleVector* platform_handles() {
120    return platform_handles_.get();
121  }
122
123  // Receive-side functions:
124
125  // Checks if the given buffer (from the "wire") looks like a valid
126  // |TransportData| buffer. (Should only be called if |buffer_size| is
127  // nonzero.) Returns null if valid, and a pointer to a human-readable error
128  // message (for debug/logging purposes) on error. Note: This checks the
129  // validity of the handle table entries (i.e., does range checking), but does
130  // not check that the validity of the actual serialized dispatcher
131  // information.
132  static const char* ValidateBuffer(size_t serialized_platform_handle_size,
133                                    const void* buffer,
134                                    size_t buffer_size);
135
136  // Gets the platform handle table from a (valid) |TransportData| buffer (which
137  // should have been validated using |ValidateBuffer()| first).
138  static void GetPlatformHandleTable(const void* transport_data_buffer,
139                                     size_t* num_platform_handles,
140                                     const void** platform_handle_table);
141
142  // Deserializes dispatchers from the given (serialized) transport data buffer
143  // (typically from a |MessageInTransit::View|) and vector of platform handles.
144  // |buffer| should be non-null and |buffer_size| should be nonzero.
145  static scoped_ptr<DispatcherVector> DeserializeDispatchers(
146      const void* buffer,
147      size_t buffer_size,
148      embedder::ScopedPlatformHandleVectorPtr platform_handles,
149      Channel* channel);
150
151 private:
152  // To allow us to make compile-assertions about |Header|, etc. in the .cc
153  // file.
154  struct PrivateStructForCompileAsserts;
155
156  // Header for the "secondary buffer"/"transport data". Must be a multiple of
157  // |MessageInTransit::kMessageAlignment| in size. Must be POD.
158  struct Header {
159    uint32_t num_handles;
160    // TODO(vtl): Not used yet:
161    uint32_t platform_handle_table_offset;
162    uint32_t num_platform_handles;
163    uint32_t unused;
164  };
165
166  struct HandleTableEntry {
167    int32_t type;     // From |Dispatcher::Type| (|kTypeUnknown| for "invalid").
168    uint32_t offset;  // Relative to the start of the "secondary buffer".
169    uint32_t size;    // (Not including any padding.)
170    uint32_t unused;
171  };
172
173  const Header* header() const {
174    return reinterpret_cast<const Header*>(buffer_.get());
175  }
176
177  size_t buffer_size_;
178  scoped_ptr<char, base::AlignedFreeDeleter> buffer_;  // Never null.
179
180  // Any platform-specific handles attached to this message (for inter-process
181  // transport). The vector (if any) owns the handles that it contains (and is
182  // responsible for closing them).
183  // TODO(vtl): With C++11, change it to a vector of |ScopedPlatformHandles|.
184  embedder::ScopedPlatformHandleVectorPtr platform_handles_;
185
186  DISALLOW_COPY_AND_ASSIGN(TransportData);
187};
188
189}  // namespace system
190}  // namespace mojo
191
192#endif  // MOJO_SYSTEM_TRANSPORT_DATA_H_
193