summaryrefslogtreecommitdiffstats
path: root/mojo/system/transport_data.h
blob: 569ff8efe8bf35323d0cce16bf718eedea4758d8 (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
// 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_SYSTEM_TRANSPORT_DATA_H_
#define MOJO_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 "mojo/embedder/platform_handle.h"
#include "mojo/system/dispatcher.h"
#include "mojo/system/system_impl_export.h"

namespace mojo {
namespace system {

// 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 sandobx-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;

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

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

  // 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.
  std::vector<embedder::PlatformHandle>* platform_handles() {
    return platform_handles_.get();
  }

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

  // 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(const void* buffer, size_t buffer_size);

  // Deserializes dispatchers from the given (serialized) transport data buffer
  // (typically from a |MessageInTransit::View|). |buffer| should be non-null
  // and |buffer_size| should be nonzero.
  static scoped_ptr<DispatcherVector> DeserializeDispatchersFromBuffer(
      const void* buffer,
      size_t buffer_size,
      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;
  };

  // The maximum possible size of a valid transport data buffer.
  static const size_t kMaxBufferSize;

  // The maximum total number of platform handles that may be attached.
  static const size_t kMaxPlatformHandles;

  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|.
  scoped_ptr<std::vector<embedder::PlatformHandle> > platform_handles_;

  DISALLOW_COPY_AND_ASSIGN(TransportData);
};

}  // namespace system
}  // namespace mojo

#endif  // MOJO_SYSTEM_TRANSPORT_DATA_H_