C++程序  |  378行  |  13.5 KB

// Copyright 2017 The Fuchsia 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 ZIRCON_FIDL_H_
#define ZIRCON_FIDL_H_

#include <assert.h>
#include <stdalign.h>
#include <stdint.h>

#include <zircon/compiler.h>
#include <zircon/types.h>

__BEGIN_CDECLS

// Fidl data types have a representation in a wire format. This wire
// format is shared by all language bindings, including C11 and C++14.
//
// The C bindings also define a representation of fidl data types. For
// a given type, the size and alignment of all parts of the type agree
// with the wire format's representation. The C representation differs
// in the representation of pointers to out-of-line allocations. On
// the wire, allocations are encoded as either present or not. In C,
// they are actual pointers. The C representation also places any
// transferred handle types (including requests) inline. The wire
// format tracks handles separately, just like the underlying channel
// transport does.
//
// Turning the wire format into the C format is called decoding.
//
// Turning the C format into the wire format is called encoding.
//
// The formats are designed to allow for in-place coding, assuming all
// out-of-line allocations placed are in traversal order (defined
// below) with natural alignment.

// Bounds.

// Various fidl types, such as strings and vectors, may be bounded. If
// no explicit bound is given, then FIDL_MAX_SIZE is implied.

#define FIDL_MAX_SIZE UINT32_MAX

// Out of line allocations.

// The fidl wire format represents potential out-of-line allocations
// (corresponding to actual pointer types in the C format) as
// uintptr_t. For allocations that are actually present and that will
// be patched up with pointers during decoding, the FIDL_ALLOC_PRESENT
// value is used. For non-present nullable allocations, the
// FIDL_ALLOC_ABSENT value is used.

#define FIDL_ALLOC_PRESENT ((uintptr_t)UINTPTR_MAX)
#define FIDL_ALLOC_ABSENT ((uintptr_t)0)

// Out of line allocations are all 8 byte aligned.
#define FIDL_ALIGNMENT ((size_t)8)
#define FIDL_ALIGN(a) (((a) + 7) & ~7)
#define FIDL_ALIGNDECL alignas(FIDL_ALIGNMENT)

// An opaque struct representing the encoding of a particular fidl
// type.
typedef struct fidl_type fidl_type_t;

// Primitive types.

// Both on the wire and once deserialized, primitive fidl types
// correspond directly to C types. There is no intermediate layer of
// typedefs. For instance, fidl's float64 is generated as double.

// All primitive types are non-nullable.

// All primitive types are naturally sized and aligned on the wire.

// fidl     C         Meaning.
// ---------------------------------------------
// bool     bool      A boolean.
// int8     int8_t    An 8 bit signed integer.
// int16    int16_t   A 16 bit signed integer.
// int32    int32_t   A 32 bit signed integer.
// int64    int64_t   A 64 bit signed integer.
// uint8    uint8_t   An 8 bit unsigned integer.
// uint16   uint16_t  A 16 bit unsigned integer.
// uint32   uint32_t  A 32 bit unsigned integer.
// uint64   uint64_t  A 64 bit unsigned integer.
// float32  float     A 32 bit IEEE-754 float.
// float64  double    A 64 bit IEEE-754 float.

// Enums.

// Fidl enums have an undering integer type (one of int8, int16,
// int32, int64, uint8, uint16, uint32, or uint64). The wire format of
// an enum and the C format of an enum are the same as the
// corresponding primitive type.

// String types.

// Fidl strings are variable-length UTF-8 strings. Strings can be
// nullable (string?) or nonnullable (string); if nullable, the null
// string is distinct from the empty string. Strings can be bounded to
// a fixed byte length (e.g. string:40? is a nullable string of at
// most 40 bytes).

// Strings are not guaranteed to be nul terminated. Strings can
// contain embedded nuls throughout their length.

// The fidl wire format dictates that strings are valid UTF-8. It is
// up to clients to provide well-formed UTF-8 and servers to check for
// it. Message encoding and decoding can, but does not by default,
// perform this check.

// All deserialized string types are represented by the fidl_string_t
// structure. This structure consists of a size (in bytes) and a
// pointer to an out-of-line allocation of uint8_t, guaranteed to be
// at least as long as the length.

// The bound on a string type is not present in the serialized format,
// but is checked as part of validation.

typedef struct fidl_string {
    // Number of UTF-8 code units (bytes), must be 0 if |data| is null.
    uint64_t size;

    // Pointer to UTF-8 code units (bytes) or null
    char* data;
} fidl_string_t;

// When encoded, an absent nullable string is represented as a
// fidl_string_t with size 0 and FIDL_ALLOC_ABSENT data, with no
// out-of-line allocation associated with it. A present string
// (nullable or not) is represented as a fidl_string_t with some size
// and with data equal to FIDL_ALLOC_PRESENT, which the decoding
// process replaces with an actual pointer to the next out-of-line
// allocation.

// All string types:

// fidl       C              Meaning
// -----------------------------------------------------------------
// string     fidl_string_t  A string of arbitrary length.
// string?    fidl_string_t  An optional string of arbitrary length.
// string:N   fidl_string_t  A string up to N bytes long.
// string:N?  fidl_string_t  An optional string up to N bytes long.

// Arrays.

// On the wire, an array of N objects of type T (array<T, N>) is
// represented the same as N contiguous Ts. Equivalently, it is
// represented the same as a nonnullable struct containing N fields
// all of type T.

// In C, this is just represented as a C array of the corresponding C
// type.

// Vector types.

// Fidl vectors are variable-length arrays of a given type T. Vectors
// can be nullable (vector<T>?) or nonnullable (vector<T>); if
// nullable, the null vector is distinct from the empty
// vector. Vectors can be bounded to a fixed element length
// (e.g. vector<T>:40? is a nullable vector of at most 40 Ts).

// All deserialized vector types are represented by the fidl_vector_t
// structure. This structure consists of a count and a pointer to the
// bytes.

// The bound on a vector type is not present in the serialized format,
// but is checked as part of validation.

typedef struct fidl_vector {
    // Number of elements, must be 0 if |data| is null.
    uint64_t count;

    // Pointer to element data or null.
    void* data;
} fidl_vector_t;

// When encoded, an absent nullable vector is represented as a
// fidl_vector_t with size 0 and FIDL_ALLOC_ABSENT data, with no
// out-of-line allocation associated with it. A present vector
// (nullable or not) is represented as a fidl_vector_t with some size
// and with data equal to FIDL_ALLOC_PRESENT, which the decoding
// process replaces with an actual pointer to the next out-of-line
// allocation.

// All vector types:

// fidl          C              Meaning
// --------------------------------------------------------------------------
// vector<T>     fidl_vector_t  A vector of T, of arbitrary length.
// vector<T>?    fidl_vector_t  An optional vector of T, of arbitrary length.
// vector<T>:N   fidl_vector_t  A vector of T, up to N elements.
// vector<T>:N?  fidl_vector_t  An optional vector of T,  up to N elements.

// Handle types.

// Handle types are encoded directly. Just like primitive types, there
// is no fidl-specific handle type. Generated fidl structures simply
// mention zx_handle_t.

// Handle types are either nullable (handle?), or not (handle); and
// either explicitly typed (e.g. handle<Channel> or handle<Job>), or
// not.

// All fidl handle types, regardless of subtype, are represented as
// zx_handle_t. The encoding tables do know the handle subtypes,
// however, for clients which wish to perform explicit checking.

// The following are the possible handle subtypes.

// process
// thread
// vmo
// channel
// event
// port
// interrupt
// iomap
// pci
// log
// socket
// resource
// eventpair
// job
// vmar
// fifo
// hypervisor
// guest
// timer

// All handle types are 4 byte sized and aligned on the wire.

// When encoded, absent nullable handles are represented as
// FIDL_HANDLE_ABSENT. Present handles, whether nullable or not, are
// represented as FIDL_HANDLE_PRESENT, which the decoding process will
// overwrite with the next handle value in the channel message.

#define FIDL_HANDLE_ABSENT ((zx_handle_t)ZX_HANDLE_INVALID)
#define FIDL_HANDLE_PRESENT ((zx_handle_t)UINT32_MAX)

// fidl        C            Meaning
// ------------------------------------------------------------------
// handle      zx_handle_t  Any valid handle.
// handle?     zx_handle_t  Any valid handle, or ZX_HANDLE_INVALID.
// handle<T>   zx_handle_t  Any valid T handle.
// handle<T>?  zx_handle_t  Any valid T handle, or ZX_HANDLE_INVALID.

// Unions.

// Fidl unions are a tagged sum type. The tag is a 4 bytes. For every
// union type, the fidl compiler generates an enum representing the
// different variants of the enum. This is followed, in C and on the
// wire, by large enough and aligned enough storage for all members of
// the union.

// Unions may be nullable. Nullable unions are represented as a
// pointer to an out of line allocation of tag-and-member. As with
// other out-of-line allocations, ones present on the wire take the
// value FIDL_ALLOC_PRESENT and those that are not are represented by
// FIDL_ALLOC_NULL. Nonnullable unions are represented inline as a
// tag-and-member.

// For each fidl union type, a corresponding C type is generated. They
// are all structs consisting of a fidl_union_tag_t discriminant,
// followed by an anonymous union of all the union members.

typedef uint32_t fidl_union_tag_t;

// fidl                 C                            Meaning
// --------------------------------------------------------------------
// union foo {...}      struct union_foo {           An inline union.
//                          fidl_union_tag_t tag;
//                          union {...};
//                      }
//
// union foo {...}?     struct union_foo*            A pointer to a
//                                                   union_foo, or else
//                                                   FIDL_ALLOC_ABSENT.

// Messages.

// All fidl messages share a common 16 byte header.

typedef struct fidl_message_header {
    zx_txid_t txid;
    // This reserved word is used by Epitaphs to represent an error value.
    uint32_t reserved0;
    uint32_t flags;
    uint32_t ordinal;
} fidl_message_header_t;

// Messages which do not have a response use zero as a special
// transaction id.

#define FIDL_TXID_NO_RESPONSE 0ul

// The system reserves the high half of the ordinal space.

#define FIDL_ORD_SYSTEM_MASK 0x80000000ul

// A FIDL message.
typedef struct fidl_msg {
    // The bytes of the message.
    //
    // The bytes of the message might be in the encoded or decoded form.
    // Functions that take a |fidl_msg_t| as an argument should document whether
    // the expect encoded or decoded messages.
    //
    // See |num_bytes| for the number of bytes in the message.
    void* bytes;

    // The handles of the message.
    //
    // See |num_bytes| for the number of bytes in the message.
    zx_handle_t* handles;

    // The number of bytes in |bytes|.
    uint32_t num_bytes;

    // The number of handles in |handles|.
    uint32_t num_handles;
} fidl_msg_t;

// An outstanding FIDL transaction.
typedef struct fidl_txn fidl_txn_t;
struct fidl_txn {
    // Replies to the outstanding request and complete the FIDL transaction.
    //
    // Pass the |fidl_txn_t| object itself as the first parameter. The |msg|
    // should already be encoded. This function always consumes any handles
    // present in |msg|.
    //
    // Call |reply| only once for each |txn| object. After |reply| returns, the
    // |txn| object is considered invalid and might have been freed or reused
    // for another purpose.
    zx_status_t (*reply)(fidl_txn_t* txn, const fidl_msg_t* msg);
};

// An epitaph is a message that a server sends just prior to closing the
// connection.  It provides an indication of why the connection is being closed.
// Epitaphs are defined in the FIDL wire format specification.  Once sent down
// the wire, the channel should be closed.
typedef struct fidl_epitaph {
    FIDL_ALIGNDECL

    // The error associated with this epitaph is stored in the reserved word of
    // the message header.  System errors must be constants of type zx_status_t,
    // which are all negative.  Positive numbers should be used for application
    // errors.  A value of ZX_OK indicates no error.
    fidl_message_header_t hdr;
} fidl_epitaph_t;

// This ordinal value is reserved for Epitaphs.
#define FIDL_EPITAPH_ORDINAL 0xFFFFFFFF

// Assumptions.

// Ensure that FIDL_ALIGNMENT is sufficient.
static_assert(alignof(bool) <= FIDL_ALIGNMENT, "");
static_assert(alignof(int8_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(int16_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(int32_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(int64_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(uint8_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(uint16_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(uint32_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(uint64_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(float) <= FIDL_ALIGNMENT, "");
static_assert(alignof(double) <= FIDL_ALIGNMENT, "");
static_assert(alignof(void*) <= FIDL_ALIGNMENT, "");
static_assert(alignof(fidl_union_tag_t) <= FIDL_ALIGNMENT, "");
static_assert(alignof(fidl_message_header_t) <= FIDL_ALIGNMENT, "");

__END_CDECLS

#endif // ZIRCON_FIDL_H_