// 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. // This file contains types/constants and functions specific to message pipes. // // Note: This header should be compilable as C. #ifndef MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_ #define MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_ #include #include "mojo/public/c/system/macros.h" #include "mojo/public/c/system/system_export.h" #include "mojo/public/c/system/types.h" // Used to refer to message objects created by |MojoCreateMessage()|. typedef uintptr_t MojoMessageHandle; #define MOJO_MESSAGE_HANDLE_INVALID ((MojoMessageHandle)0) // Flags passed to |MojoCreateMessagePipe()| via |MojoCreateMessagePipeOptions|. // See values defined below. typedef uint32_t MojoCreateMessagePipeFlags; // No flags. Default behavior. #define MOJO_CREATE_MESSAGE_PIPE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoCreateMessagePipe()|. struct MOJO_ALIGNAS(8) MojoCreateMessagePipeOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoCreateMessagePipeFlags|. MojoCreateMessagePipeFlags flags; }; MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment"); MOJO_STATIC_ASSERT(sizeof(MojoCreateMessagePipeOptions) == 8, "MojoCreateMessagePipeOptions has wrong size"); // Flags passed to |MojoWriteMessage()| via |MojoWriteMessageOptions|. See // values defined below. typedef uint32_t MojoWriteMessageFlags; // No flags. Default behavior. #define MOJO_WRITE_MESSAGE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoWriteMessage()|. struct MOJO_ALIGNAS(8) MojoWriteMessageOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoWriteMessageFlags|. MojoWriteMessageFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoWriteMessageOptions) == 8, "MojoWriteMessageOptions has wrong size"); // Flags passed to |MojoReadMessage()| via |MojoReadMessageOptions|. See values // defined below. typedef uint32_t MojoReadMessageFlags; // No flags. Default behavior. #define MOJO_READ_MESSAGE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoReadMessage()|. struct MOJO_ALIGNAS(8) MojoReadMessageOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoReadMessageFlags|. MojoReadMessageFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoReadMessageOptions) == 8, "MojoReadMessageOptions has wrong size"); // Flags passed to |MojoFuseMessagePipes()| via |MojoFuseMessagePipeOptions|. // See values defined below. typedef uint32_t MojoFuseMessagePipesFlags; // No flags. Default behavior. #define MOJO_FUSE_MESSAGE_PIPES_FLAG_NONE ((uint32_t)0) // Options passed to |MojoFuseMessagePipes()|. struct MOJO_ALIGNAS(8) MojoFuseMessagePipesOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoFuseMessagePipesFlags|. MojoFuseMessagePipesFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoFuseMessagePipesOptions) == 8, "MojoFuseMessagePipesOptions has wrong size"); // Flags passed to |MojoCreateMessage()| via |MojoCreateMessageOptions|. typedef uint32_t MojoCreateMessageFlags; // No flags. Default behavior. #define MOJO_CREATE_MESSAGE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoCreateMessage()|. struct MOJO_ALIGNAS(8) MojoCreateMessageOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoCreateMessageFlags|. MojoCreateMessageFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoCreateMessageOptions) == 8, "MojoCreateMessageOptions has wrong size"); // Flags passed to |MojoSerializeMessage()| via |MojoSerializeMessageOptions|. typedef uint32_t MojoSerializeMessageFlags; // No flags. Default behavior. #define MOJO_SERIALIZE_MESSAGE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoSerializeMessage()|. struct MOJO_ALIGNAS(8) MojoSerializeMessageOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoSerializeMessageFlags|. MojoSerializeMessageFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoSerializeMessageOptions) == 8, "MojoSerializeMessageOptions has wrong size"); // Flags passed to |MojoAppendMessageData()| via |MojoAppendMessageDataOptions|. typedef uint32_t MojoAppendMessageDataFlags; // No flags. Default behavior. #define MOJO_APPEND_MESSAGE_DATA_FLAG_NONE ((uint32_t)0) // If set, this comments the resulting (post-append) message size as the final // size of the message payload, in terms of both bytes and attached handles. #define MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE \ ((MojoAppendMessageDataFlags)1) // Options passed to |MojoAppendMessageData()|. struct MOJO_ALIGNAS(8) MojoAppendMessageDataOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoAppendMessageDataFlags|. MojoAppendMessageDataFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoAppendMessageDataOptions) == 8, "MojoAppendMessageDataOptions has wrong size"); // Flags passed to |MojoGetMessageData()| via |MojoGetMessageDataOptions|. typedef uint32_t MojoGetMessageDataFlags; // No flags. Default behavior. #define MOJO_GET_MESSAGE_DATA_FLAG_NONE ((uint32_t)0) // Ignores attached handles when retrieving message data. This leaves any // attached handles intact and owned by the message object. #define MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES ((uint32_t)1) // Options passed to |MojoGetMessageData()|. struct MOJO_ALIGNAS(8) MojoGetMessageDataOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoGetMessageDataFlags|. MojoGetMessageDataFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoGetMessageDataOptions) == 8, "MojoGetMessageDataOptions has wrong size"); // Flags passed to |MojoSetMessageContext()| via |MojoSetMessageContextOptions|. typedef uint32_t MojoSetMessageContextFlags; // No flags. Default behavior. #define MOJO_SET_MESSAGE_CONTEXT_FLAG_NONE ((uint32_t)0) // Options passed to |MojoSetMessageContext()|. struct MOJO_ALIGNAS(8) MojoSetMessageContextOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoSetMessageContextFlags|. MojoSetMessageContextFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoSetMessageContextOptions) == 8, "MojoSetMessageContextOptions has wrong size"); // Flags passed to |MojoGetMessageContext()| via |MojoGetMessageContextOptions|. typedef uint32_t MojoGetMessageContextFlags; // No flags. Default behavior. #define MOJO_GET_MESSAGE_CONTEXT_FLAG_NONE ((uint32_t)0) // Options passed to |MojoGetMessageContext()|. struct MOJO_ALIGNAS(8) MojoGetMessageContextOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoGetMessageContextFlags|. MojoGetMessageContextFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoGetMessageContextOptions) == 8, "MojoGetMessageContextOptions has wrong size"); // Flags passed to |MojoNotifyBadMessage()| via |MojoNotifyBadMessageOptions|. typedef uint32_t MojoNotifyBadMessageFlags; // No flags. Default behavior. #define MOJO_NOTIFY_BAD_MESSAGE_FLAG_NONE ((uint32_t)0) // Options passed to |MojoNotifyBadMessage()|. struct MOJO_ALIGNAS(8) MojoNotifyBadMessageOptions { // The size of this structure, used for versioning. uint32_t struct_size; // See |MojoNotifyBadMessageFlags|. MojoNotifyBadMessageFlags flags; }; MOJO_STATIC_ASSERT(sizeof(MojoNotifyBadMessageOptions) == 8, "MojoNotifyBadMessageOptions has wrong size"); #ifdef __cplusplus extern "C" { #endif // A callback which can serialize a message given some context. Passed to // |MojoSetMessageContext()| along with a context it knows how to serialize. // See |MojoSetMessageContext()| for more details. // // |message| is a message object which had |context| attached. // |context| the context which was attached to |message|. // // Note that the context is always detached from the message immediately before // this callback is invoked, and that the associated destructor (if any) is also // invoked on |context| immediately after the serializer returns. typedef void (*MojoMessageContextSerializer)(MojoMessageHandle message, uintptr_t context); // A callback which can be used to destroy a message context after serialization // or in the event that the message to which it's attached is destroyed without // ever being serialized. typedef void (*MojoMessageContextDestructor)(uintptr_t context); // Note: See the comment in functions.h about the meaning of the "optional" // label for pointer parameters. // Creates a message pipe, which is a bidirectional communication channel for // framed data (i.e., messages). Messages can contain plain data and/or Mojo // handles. // // |options| may be set to null for a message pipe with the default options. // // On success, |*message_pipe_handle0| and |*message_pipe_handle1| are set to // handles for the two endpoints (ports) for the message pipe. // // Returns: // |MOJO_RESULT_OK| on success. // |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., // |*options| is invalid). // |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has // been reached. MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessagePipe( const struct MojoCreateMessagePipeOptions* options, // Optional. MojoHandle* message_pipe_handle0, // Out. MojoHandle* message_pipe_handle1); // Out. // Writes a message to the message pipe endpoint given by |message_pipe_handle|. // // Note that regardless of success or failure, |message| is destroyed by this // call and therefore invalidated. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| on success (i.e., the message was enqueued). // |MOJO_RESULT_INVALID_ARGUMENT| if |message_pipe_handle| or |message| is // invalid. // |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed. // Note that closing an endpoint is not necessarily synchronous (e.g., // across processes), so this function may succeed even if the other // endpoint has been closed (in which case the message would be dropped). // |MOJO_RESULT_NOT_FOUND| if |message| has neither a context nor serialized // buffer attached and therefore has nothing to be written. MOJO_SYSTEM_EXPORT MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, MojoMessageHandle message, const struct MojoWriteMessageOptions* options); // Reads the next message from a message pipe and returns a message as an opaque // message handle. The returned message must eventually be destroyed using // |MojoDestroyMessage()|. // // Message payload and handles can be accessed using |MojoGetMessageData()|. For // Unserialized messages, context may be accessed using // |MojoGetMessageContext()|. // // |options| may be null. |message| must be non-null. // // Returns: // |MOJO_RESULT_OK| on success (i.e., a message was actually read). // |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid. // |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed // and there are no more messages to read. // |MOJO_RESULT_SHOULD_WAIT| if no message was available to be read. MOJO_SYSTEM_EXPORT MojoResult MojoReadMessage(MojoHandle message_pipe_handle, const struct MojoReadMessageOptions* options, MojoMessageHandle* message); // Fuses two message pipe endpoints together. Given two pipes: // // A <-> B and C <-> D // // Fusing handle B and handle C results in a single pipe: // // A <-> D // // Handles B and C are ALWAYS closed. Any unread messages at C will eventually // be delivered to A, and any unread messages at B will eventually be delivered // to D. // // NOTE: A handle may only be fused if it is an open message pipe handle which // has not been written to. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| on success. // |MOJO_RESULT_FAILED_PRECONDITION| if both handles were valid message pipe // handles but could not be merged (e.g. one of them has been written to). // |MOJO_INVALID_ARGUMENT| if either handle is not a fusable message pipe // handle. MOJO_SYSTEM_EXPORT MojoResult MojoFuseMessagePipes(MojoHandle handle0, MojoHandle handle1, const struct MojoFuseMessagePipesOptions* options); // Creates a new message object which may be sent over a message pipe via // |MojoWriteMessage()|. Returns a handle to the new message object in // |*message|. // // In its initial state the message object cannot be successfully written to a // message pipe, but must first have either an opaque context or some serialized // data attached (see |MojoSetMessageContext()| and // |MojoAppendMessageData()|). // // NOTE: Unlike other types of Mojo API objects, messages are NOT thread-safe // and thus callers of message-related APIs must be careful to restrict usage of // any given |MojoMessageHandle| to a single thread at a time. // // Returns: // |MOJO_RESULT_OK| if a new message was created. |*message| contains a handle // to the new message object upon return. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is null. MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessage(const struct MojoCreateMessageOptions* options, MojoMessageHandle* message); // Destroys a message object created by |MojoCreateMessage()| or // |MojoReadMessage()|. // // |message|: The message to destroy. Note that if a message has been written // to a message pipe using |MojoWriteMessage()|, it is neither necessary nor // valid to attempt to destroy it. // // Returns: // |MOJO_RESULT_OK| if |message| was valid and has been freed. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| was not a valid message. MOJO_SYSTEM_EXPORT MojoResult MojoDestroyMessage(MojoMessageHandle message); // Forces a message to be serialized in-place if not already serialized. // // Returns: // |MOJO_RESULT_OK| if |message| was not serialized and is now serialized. // In this case its thunks were invoked to perform serialization and // ultimately destroy its associated context. The message may still be // written to a pipe or decomposed by |MojoGetMessageData()|. // |MOJO_RESULT_FAILED_PRECONDITION| if |message| was already serialized. // |MOJO_RESULT_NOT_FOUND| if |message| cannot be serialized (i.e. it was // created with null |MojoMessageContextSerializer|.) // |MOJO_RESULT_BUSY| if one or more handles provided by the user context // reported itself as busy during the serialization attempt. In this case // all serialized handles are closed automatically. // |MOJO_RESULT_ABORTED| if some other unspecified error occurred during // handle serialization. In this case all serialized handles are closed // automatically. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is not a valid message handle. // // Note that unserialized messages may be successfully transferred from one // message pipe endpoint to another without ever being serialized. This function // allows callers to coerce eager serialization. MOJO_SYSTEM_EXPORT MojoResult MojoSerializeMessage(MojoMessageHandle message, const struct MojoSerializeMessageOptions* options); // Appends data to a message object. // // |message|: The message. // |additional_payload_size|: The number of bytes by which to extend the payload // of the message. // |handles|: Handles to be appended to the message. May be null iff // |num_handles| is 0. // |num_handles|: The number of handles to be appended to the message. // // |options| may be null. // // If this call succeeds, |*buffer| will contain the address of the data's // storage if |buffer| was non-null, and if |buffer_size| was non-null then // |*buffer_size| will contain the storage capacity. The caller may write // message contents here. // // Note that while the size of the returned buffer may exceed the total // requested size accumulated over one or more calls to // |MojoAppendMessageData()|, only the extent of caller's requested capacity is // considered to be part of the message. // // A message with attached data must have its capacity finalized before it can // be transmitted by calling this function with // |MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE| set in |options->flags|. Note // that even after this happens, the returned |*buffer| remains valid and // writable until the message is passed to either |MojoWriteMessage()| or // |MojoDestroyMessage()|. // // Ownership of all handles in |handles| is transferred to the message object if // and ONLY if this operation succeeds and returns |MOJO_RESULT_OK|. Otherwise // the caller retains ownership. // // Returns: // |MOJO_RESULT_OK| upon success. The message's data buffer and size are // stored to |*buffer| and |*buffer_size| respectively. Any previously // appended data remains intact but may be moved in the event that // |*buffer| itself is moved. If // |MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE| was set in // |options->flags|, the message is ready for transmission. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is not a valid message object; // if |num_handles| is non-zero but |handles| is null; or if any handle in // |handles| is invalid. // |MOJO_RESULT_RESOURCE_EXHAUSTED| if |additional_payload_size| or // |num_handles| exceeds some implementation- or embedder-defined maximum. // |MOJO_RESULT_FAILED_PRECONDITION| if |message| has a context attached. // |MOJO_RESULT_BUSY| if one or more handles in |handles| is currently busy // and unable to be serialized. MOJO_SYSTEM_EXPORT MojoResult MojoAppendMessageData(MojoMessageHandle message, uint32_t payload_size, const MojoHandle* handles, uint32_t num_handles, const struct MojoAppendMessageDataOptions* options, void** buffer, uint32_t* buffer_size); // Retrieves data attached to a message object. // // |message|: The message. // |num_bytes|: An output parameter which will receive the total size in bytes // of the message's payload. // |buffer|: An output parameter which will receive the address of a buffer // containing exactly |*num_bytes| bytes of payload data. This buffer // address is not owned by the caller and is only valid as long as the // message handle in |message| is valid. // |num_handles|: An input/output parameter. On input, if not null, this points // to value specifying the available capacity (in number of handles) of // |handles|. On output, if not null, this will point to a value specifying // the actual number of handles available in the serialized message. // |handles|: A buffer to contain up to (input) |*num_handles| handles. May be // null if |num_handles| is null or |*num_handles| is 0. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| if |message| is a message with data attached and the // provided handle storage is sufficient to contain all handles attached // to the message. If |MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES| was set // in |options->flags|, any attached handles in the message are left // intact and both |handles| and |num_handles| are ignored. Otherwise // ownership of any attached handles is transferred to the caller, and // |MojoGetMessageData()| may no longer be called on |message| unless // |MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES| is used. // |MOJO_RESULT_INVALID_ARGUMENT| if |num_handles| is non-null and // |*num_handles| is non-zero, but |handles| is null; or if |message| is // not a valid message handle. // |MOJO_RESULT_FAILED_PRECONDITION| if |message| is not a fully serialized // message. The caller may use |MojoSerializeMessage()| and try again, // or |MojoAppendMessageData()| with the // |MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE| flag set to complete a // partially serialized |message|. // |MOJO_RESULT_NOT_FOUND| if the message's handles (if any) contents have // already been extracted (or have failed to be extracted) by a previous // call to |MojoGetMessageData()|. // |MOJO_RESULT_RESOURCE_EXHAUSTED| if |num_handles| is null and there are // handles attached to the message, or if |*num_handles| on input is less // than the number of handles attached to the message. Also may be // returned if |num_bytes| or |buffer| is null and the message has a non- // empty payload. Note that if |MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES| // is set in |options->flags| any current or previously attached handles // are ignored. // |MOJO_RESULT_ARBORTED| if the message is in an invalid state and its data // and/or handles are unrecoverable. The message is left in this state but // future calls to this API will yield the same result. MOJO_SYSTEM_EXPORT MojoResult MojoGetMessageData(MojoMessageHandle message, const struct MojoGetMessageDataOptions* options, void** buffer, uint32_t* num_bytes, MojoHandle* handles, uint32_t* num_handles); // Sets an opaque context value on a message object. The presence of an opaque // context is mutually exclusive to the presence of message data. // // |context| is the context value to associate with this message, and // |serializer| is a function which may be called at some later time to convert // |message| to a serialized message object using |context| as input. See // |MojoMessageContextSerializer| for more details. |destructor| is a function // which may be called to allow the user to cleanup state associated with // |context| after serialization or in the event that the message is destroyed // without ever being serialized. // // Typically a caller will use |context| as an opaque pointer to some heap // object which is effectively owned by the message once this returns. In this // way, messages can be sent over a message pipe to a peer endpoint in the same // process as the sender without performing a serialization step. // // If the message does need to cross a process boundary or is otherwise // forced to serialize (see |MojoSerializeMessage()| below), it will be // serialized by invoking |serializer|. // // If |serializer| is null, the created message cannot be serialized. Subsequent // calls to |MojoSerializeMessage()| on the created message, or any attempt to // transmit the message across a process boundary, will fail. // // If |destructor| is null, it is assumed that no cleanup is required after // serializing or destroying a message with |context| attached. // // A |context| value of zero is invalid, and setting this on a message // effectively removes its context. This is necessary if the caller wishes to // attach data to the message or if the caller wants to destroy the message // object without triggering |destructor|. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| if the opaque context value was successfully set. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is not a valid message object; // |options| is non-null and |*options| contains one or more malformed // fields; or |context| is zero but either |serializer| or |destructor| is // non-null. // |MOJO_RESULT_ALREADY_EXISTS| if |message| already has a non-zero context. // |MOJO_RESULT_FAILED_PRECONDITION| if |message| has data attached. MOJO_SYSTEM_EXPORT MojoResult MojoSetMessageContext(MojoMessageHandle message, uintptr_t context, MojoMessageContextSerializer serializer, MojoMessageContextDestructor destructor, const struct MojoSetMessageContextOptions* options); // Retrieves a message object's opaque context value. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| if |message| is a valid message object. |*context| // contains its opaque context value, which may be zero. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is not a valid message object // or |options| is non-null and |*options| contains one or more malformed // fields. MOJO_SYSTEM_EXPORT MojoResult MojoGetMessageContext(MojoMessageHandle message, const struct MojoGetMessageContextOptions* options, uintptr_t* context); // Notifies the system that a bad message was received on a message pipe, // according to whatever criteria the caller chooses. This ultimately tries to // notify the embedder about the bad message, and the embedder may enforce some // policy for dealing with the source of the message (e.g. close the pipe, // terminate, a process, etc.) The embedder may not be notified if the calling // process has lost its connection to the source process. // // |message|: The message to report as bad. // |error|: An error string which may provide the embedder with context when // notified of this error. // |error_num_bytes|: The length of |error| in bytes. // // |options| may be null. // // Returns: // |MOJO_RESULT_OK| if successful. // |MOJO_RESULT_INVALID_ARGUMENT| if |message| is not a valid message. MOJO_SYSTEM_EXPORT MojoResult MojoNotifyBadMessage(MojoMessageHandle message, const char* error, uint32_t error_num_bytes, const struct MojoNotifyBadMessageOptions* options); #ifdef __cplusplus } // extern "C" #endif #endif // MOJO_PUBLIC_C_SYSTEM_MESSAGE_PIPE_H_