// 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 #include #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" #include "mojo/public/cpp/system/macros.h" namespace mojo { namespace edk { // 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 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(); explicit TransportData(scoped_ptr dispatchers); // This is used for users of |MessageInTransit|/|TransportData|/|RawChannel| // that want to simply transport data and platform handles, and not // |Dispatcher|s. (|Header| will be present, and zero except for // |num_platform_handles|, and |platform_handle_table_offset| if necessary.) explicit TransportData( ScopedPlatformHandleVectorPtr platform_handles, size_t serialized_platform_handle_size); ~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 PlatformHandleVector* platform_handles() const { return platform_handles_.get(); } 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 DeserializeDispatchers( const void* buffer, size_t buffer_size, ScopedPlatformHandleVectorPtr platform_handles); 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 { // TODO(vtl): Should I make |Dispatcher::Type| an |int32_t| enum class? int32_t type; // From |Dispatcher::Type| (|UNKNOWN| 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(buffer_.get()); } size_t buffer_size_; scoped_ptr 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 |ScopedPlatformHandle|s. ScopedPlatformHandleVectorPtr platform_handles_; MOJO_DISALLOW_COPY_AND_ASSIGN(TransportData); }; } // namespace edk } // namespace mojo #endif // MOJO_EDK_SYSTEM_TRANSPORT_DATA_H_