summaryrefslogtreecommitdiff
path: root/mojo/public/c/system/message_pipe.h
blob: 9f222f9aa819c9a8805275ef2394cb74cc00c559 (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
// 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 <stdint.h>

#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_