1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495 |
- // Copyright 2022 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 IPCZ_INCLUDE_IPCZ_IPCZ_H_
- #define IPCZ_INCLUDE_IPCZ_IPCZ_H_
- // ipcz is a cross-platform C library for interprocess communication (IPC) which
- // supports efficient routing and data transfer over a large number of
- // dynamically relocatable messaging endpoints.
- //
- // ipcz operates in terms of a small handful of abstractions encapsulated in
- // this header: nodes, portals, parcels, drivers, boxes, and traps.
- //
- // NOTE: This header is intended to compile under C++11 or newer, and C99 or
- // newer. The ABI defined here can be considered stable.
- //
- // Glossary
- // --------
- // *Nodes* are used by ipcz to model isolated units of an application. A typical
- // application will create one ipcz node within each OS process it controls.
- //
- // *Portals* are messaging endpoints which belong to a specific node. Portals
- // are created in entangled pairs: whatever goes into one portal comes out the
- // other (its "peer"). Pairs may be created local to a single node, or they may
- // be created to span two nodes. Portals may also be transferred freely through
- // other portals.
- //
- // *Parcels* are the unit of communication between portals. Parcels can contain
- // arbitrary application data as well as ipcz handles. Handles within a parcel
- // are used to transfer objects (namely other portals, or driver-defined
- // objects) from one portal to another, potentially on a different node.
- //
- // *Traps* provide a flexible mechanism to observe interesting portal state
- // changes such as new parcels arriving or a portal's peer being closed.
- //
- // *Drivers* are provided by applications to implement platform-specific IPC
- // details. They may also define new types of objects to be transmitted in
- // parcels via boxes.
- //
- // *Boxes* are opaque objects used to wrap driver-defined objects for seamless
- // transmission across portals. Drivers define how to serialize and deserialize
- // such objects, and applications use the Box() and Unbox() APIs to go between
- // concrete driver objects and transferrable handles.
- //
- // Overview
- // --------
- // To use ipcz effectively, an application must create multiple nodes to be
- // interconnected. One node must be designated as the "broker" by the
- // application (see CreateNode() flags). The broker is used by ipcz to
- // coordinate certain types of internal transactions which demand a heightened
- // level of trust and capability, so a broker node should always live in a more
- // trustworthy process. For example in Chrome, the browser process is
- // designated as the broker.
- //
- // In order for a node to communicate with other nodes in the system, the
- // application must explicitly connect it to ONE other node using the
- // ConnectNode() API. Once this is done, ipcz can automatically connect the node
- // to additional other nodes as needed for efficient portal operation.
- //
- // In the example below, assume node A is designated as the broker. Nodes A and
- // B have been connected directly by ConnectNode() calls in the application.
- // Nodes A and C have been similarly connected:
- //
- // ┌───────┐
- // ConnectNode() │ │ ConnectNode()
- // ┌──────────>O A O<───────────┐
- // │ │ │ │
- // │ └───────┘ │
- // │ │
- // v ConnectNode() v ConnectNode()
- // ┌───O───┐ ┌───O───┐
- // │ │ │ │
- // │ B │ │ C │
- // │ │ │ │
- // └───────┘ └───────┘
- //
- // ConnectNode() establishes initial portal pairs to link the two nodes
- // together, illustrated above as "O"s. Once ConnectNode() returns, the
- // application may immediately begin transmitting parcels through these portals.
- //
- // Now suppose node B creates a new local pair of portals (using OpenPortals())
- // and sends one of those new portals in a parcel through its
- // already-established portal to node A. The sent portal is effectively
- // transferred to node A, and because its entangled peer still lives on node B
- // there are now TWO portal pairs between nodes A and B:
- //
- // ┌───────┐
- // │ │
- // ┌──────────>O A O<───────────┐
- // │ ┌────────>O │ │
- // │ │ └───────┘ │
- // │ │ │
- // v v v
- // ┌───O─O─┐ ┌───O───┐
- // │ │ │ │
- // │ B │ │ C │
- // │ │ │ │
- // └───────┘ └───────┘
- //
- // Finally, suppose now the application takes this new portal on node A and
- // sends it further along, through node A's already-established portal to node
- // C. Because the transferred portal's peer still lives on node B, there is now
- // a portal pair spanning nodes B and C:
- //
- // ┌───────┐
- // │ │
- // ┌──────────>O A O<───────────┐
- // │ │ │ │
- // │ └───────┘ │
- // │ │
- // v v
- // ┌───O───┐ ┌───O───┐
- // │ │ │ │
- // │ B O────────────────────────O C │
- // │ │ │ │
- // └───────┘ └───────┘
- //
- // These two nodes were never explicitly connected by the application, but ipcz
- // ensures that the portals will operate as expected. Behind the scenes, ipcz
- // achieves this by establishing a direct, secure, and efficient communication
- // channel between nodes B and C.
- #include <stddef.h>
- #include <stdint.h>
- #define IPCZ_NO_FLAGS ((uint32_t)0)
- // Helper to clarify flag definitions.
- #define IPCZ_FLAG_BIT(bit) ((uint32_t)(1u << bit))
- // Opaque handle to an ipcz object.
- typedef uintptr_t IpczHandle;
- // An IpczHandle value which is always invalid. Note that arbitrary non-zero
- // values are not necessarily valid either, but zero is never valid.
- #define IPCZ_INVALID_HANDLE ((IpczHandle)0)
- // Generic result code for all ipcz operations. See IPCZ_RESULT_* values below.
- typedef int IpczResult;
- // Specific meaning of each value depends on context, but IPCZ_RESULT_OK always
- // indicates success. These values are derived from common status code
- // definitions across Google software.
- #define IPCZ_RESULT_OK ((IpczResult)0)
- #define IPCZ_RESULT_CANCELLED ((IpczResult)1)
- #define IPCZ_RESULT_UNKNOWN ((IpczResult)2)
- #define IPCZ_RESULT_INVALID_ARGUMENT ((IpczResult)3)
- #define IPCZ_RESULT_DEADLINE_EXCEEDED ((IpczResult)4)
- #define IPCZ_RESULT_NOT_FOUND ((IpczResult)5)
- #define IPCZ_RESULT_ALREADY_EXISTS ((IpczResult)6)
- #define IPCZ_RESULT_PERMISSION_DENIED ((IpczResult)7)
- #define IPCZ_RESULT_RESOURCE_EXHAUSTED ((IpczResult)8)
- #define IPCZ_RESULT_FAILED_PRECONDITION ((IpczResult)9)
- #define IPCZ_RESULT_ABORTED ((IpczResult)10)
- #define IPCZ_RESULT_OUT_OF_RANGE ((IpczResult)11)
- #define IPCZ_RESULT_UNIMPLEMENTED ((IpczResult)12)
- #define IPCZ_RESULT_INTERNAL ((IpczResult)13)
- #define IPCZ_RESULT_UNAVAILABLE ((IpczResult)14)
- #define IPCZ_RESULT_DATA_LOSS ((IpczResult)15)
- // Helper to specify explicit struct alignment across C and C++ compilers.
- #if defined(__cplusplus)
- #define IPCZ_ALIGN(alignment) alignas(alignment)
- #elif defined(__GNUC__)
- #define IPCZ_ALIGN(alignment) __attribute__((aligned(alignment)))
- #elif defined(_MSC_VER)
- #define IPCZ_ALIGN(alignment) __declspec(align(alignment))
- #else
- #error "IPCZ_ALIGN() is not defined for your compiler."
- #endif
- // Helper to generate the smallest constant value which is aligned with
- // `alignment` and at least as large as `value`.
- #define IPCZ_ALIGNED(value, alignment) \
- ((((value) + ((alignment)-1)) / (alignment)) * (alignment))
- // Helper used to explicitly specify calling convention or other
- // compiler-specific annotations for each API function.
- #if defined(IPCZ_API_OVERRIDE)
- #define IPCZ_API IPCZ_API_OVERRIDE
- #elif defined(_WIN32)
- #define IPCZ_API __cdecl
- #else
- #define IPCZ_API
- #endif
- // An opaque handle value created by an IpczDriver implementation. ipcz uses
- // such handles to provide relevant context when calling back into the driver.
- typedef uintptr_t IpczDriverHandle;
- #define IPCZ_INVALID_DRIVER_HANDLE ((IpczDriverHandle)0)
- // Flags given to the ipcz activity handler by a driver transport to notify ipcz
- // about incoming data or state changes.
- typedef uint32_t IpczTransportActivityFlags;
- // If set, the driver encountered an unrecoverable error using the transport and
- // ipcz should discard it. Note that the driver is free to issue such
- // notifications many times as long as it remans active, but ipcz will generally
- // request deactivation ASAP once an error is signaled.
- #define IPCZ_TRANSPORT_ACTIVITY_ERROR IPCZ_FLAG_BIT(0)
- // When ipcz wants to deactivate a transport, it invokes the driver's
- // DeactivateTransport() function. Once the driver has finished any clean up and
- // can ensure that the transport's activity handler will no longer be invoked,
- // it must then invoke the activity handler one final time with this flag set.
- // This finalizes deactivation and allows ipcz to free any associated resources.
- #define IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED IPCZ_FLAG_BIT(1)
- #if defined(__cplusplus)
- extern "C" {
- #endif
- // Notifies ipcz of activity on a transport. `transport` must be a handle to a
- // transport which is currently activated. The `transport` handle is acquired
- // exclusively by the driver transport via an ipcz call to the driver's
- // ActivateTransport(), which also provides the handle to the driver.
- //
- // The driver must use this function to feed incoming data and driver handles
- // from the transport to ipcz, or to inform ipcz of any error conditions
- // resulting in unexpected and irrecoverable dysfunction of the transport.
- //
- // If the driver encounters an unrecoverable error while performing I/O on the
- // transport, it should invoke this with the IPCZ_TRANSPORT_ACTIVITY_ERROR flag
- // to instigate deactivation of the transport by ipcz via a subsequent
- // DeactivateTransport() call.
- //
- // `options` is currently unused and must be null.
- //
- // NOTE: It is the driver's responsibility to ensure that calls to this function
- // for the same value of `transport` are mututally exclusive. Overlapping calls
- // are unsafe and will result in undefined behavior.
- typedef IpczResult(IPCZ_API* IpczTransportActivityHandler)(
- IpczHandle transport, // in
- const void* data, // in
- size_t num_bytes, // in
- const IpczDriverHandle* driver_handles, // in
- size_t num_driver_handles, // in
- IpczTransportActivityFlags flags, // in
- const void* options); // in
- // Structure to be filled in by a driver's GetSharedMemoryInfo().
- struct IPCZ_ALIGN(8) IpczSharedMemoryInfo {
- // The exact size of this structure in bytes. Set by ipcz before passing the
- // structure to the driver.
- size_t size;
- // The size of the shared memory region in bytes.
- size_t region_num_bytes;
- };
- // IpczDriver is a function table to be populated by the application and
- // provided to ipcz when creating a new node. The driver implements concrete
- // I/O operations to facilitate communication between nodes, giving embedding
- // systems full control over choice of OS-specific transport mechanisms and I/O
- // scheduling decisions.
- //
- // The driver API is meant to be used by both the application embedding ipcz,
- // particularly for creating transports to make initial contact between nodes,
- // as well as by ipcz itself to delegate creation and management of new
- // transports which ipcz brokers between nodes.
- struct IPCZ_ALIGN(8) IpczDriver {
- // The exact size of this structure in bytes. Must be set accurately by the
- // application before passing this structure to any ipcz API functions.
- size_t size;
- // Called by ipcz to request that the driver release the object identified by
- // `handle`.
- IpczResult(IPCZ_API* Close)(IpczDriverHandle handle, // in
- uint32_t flags, // in
- const void* options); // in
- // Serializes a driver object identified by `handle` into a collection of
- // bytes and readily transmissible driver objects, for eventual transmission
- // over `transport`. At a minimum this must support serialization of transport
- // and memory objects allocated by ipcz through the driver. Any other driver
- // objects intended for applications to box and transmit through portals must
- // also be serializable here.
- //
- // If the specified object is invalid or unserializable, the driver must
- // ignore all other arguments (including `transport`) and return
- // IPCZ_RESULT_INVALID_ARGUMENT.
- //
- // If the object can be serialized but success may depend on the value of
- // `transport`, and `transport` is IPCZ_INVALID_DRIVER_HANDLE, the driver must
- // return IPCZ_RESULT_ABORTED. ipcz may invoke Serialize() in this way to
- // query whether a specific object can be serialized at all, even when it
- // doesn't have a specific transport in mind.
- //
- // If the object can be serialized or transmitted as-is and `transport` is
- // valid, but the serialized outputs would not be transmissible over
- // `transport` specifically, the driver must ignore all other arguments and
- // return IPCZ_RESULT_PERMISSION_DENIED. This implies that neither end of
- // `transport` is sufficiently privileged or otherwise able to transfer the
- // object directly, and in this case ipcz may instead attempt to relay the
- // object through a more capable broker node.
- //
- // For all other outcomes, the object identified by `handle` is considered to
- // be serializable and ultimately transmissible.
- //
- // `num_bytes` and `num_handles` on input point to the capacities of the
- // respective output buffers provided by ipcz. If either capacity pointer is
- // null, a capacity of zero is implied; and if either input capacity is zero,
- // the corresponding input buffer may be null.
- //
- // Except in the failure modes described above, the driver must update any
- // non-null capacity input to reflect the exact capacity required to serialize
- // the object. For example if `num_bytes` is non-null and the object
- // serializes to 8 bytes of data, `*num_bytes` must be set to 8 upon return.
- //
- // If the required data or handle capacity is larger than the respective input
- // capacity, the driver must return IPCZ_RESULT_RESUORCE_EXHAUSTED without
- // modifying the contents of either `data` or `handles` buffers.
- //
- // Finally, if the input capacities were both sufficient, the driver must fill
- // `data` and `handles` with a serialized representation of the object and
- // return IPCZ_RESULT_OK. In this case ipcz relinquishes `handle` and will no
- // longer refer to it unless the driver outputs it back in `handles`, implying
- // that it was already transmissible as-is.
- IpczResult(IPCZ_API* Serialize)(IpczDriverHandle handle, // in
- IpczDriverHandle transport, // in
- uint32_t flags, // in
- const void* options, // in
- void* data, // out
- size_t* num_bytes, // in/out
- IpczDriverHandle* handles, // out
- size_t* num_handles); // in/out
- // Deserializes a driver object from a collection of bytes and transmissible
- // driver objects which which was originally produced by Serialize() and
- // received on the calling node via `transport`.
- //
- // Any return value other than IPCZ_RESULT_OK indicates an error and implies
- // that `handle` is unmodified. Otherwise `handle` must contain a valid driver
- // handle to the deserialized object.
- IpczResult(IPCZ_API* Deserialize)(
- const void* data, // in
- size_t num_bytes, // in
- const IpczDriverHandle* driver_handles, // in
- size_t num_driver_handles, // in
- IpczDriverHandle transport, // in
- uint32_t flags, // in
- const void* options, // in
- IpczDriverHandle* handle); // out
- // Creates a new pair of entangled bidirectional transports, returning them in
- // `new_transport0` and `new_transport1`.
- //
- // The input `transport0` and `transport1` are provided for context which may
- // be important to the driver: the output transport in `new_transport0` will
- // be sent over `transport0`, while the output transport in `new_transport1`
- // will be sent over `transport1`. That is, the new transport is being created
- // to establish a direct link between the remote node on `transport0` and the
- // remote node on `transport1`.
- //
- // Any return value other than IPCZ_RESULT_OK indicates an error and implies
- // that `new_transport0` and `new_transport1` are unmodified.
- IpczResult(IPCZ_API* CreateTransports)(
- IpczDriverHandle transport0, // in
- IpczDriverHandle transport1, // in
- uint32_t flags, // in
- const void* options, // in
- IpczDriverHandle* new_transport0, // out
- IpczDriverHandle* new_transport1); // out
- // Called by ipcz to activate a transport. `driver_transport` is the
- // driver-side handle assigned to the transport by the driver, either as given
- // to ipcz via ConnectNode(), or as returned by the driver from an ipcz call
- // out to CreateTransports().
- //
- // `transport` is a handle the driver can use when calling `activity_handler`
- // to update ipcz regarding any incoming data or state changes from the
- // transport.
- //
- // Before this returns, the driver should establish any I/O monitoring or
- // scheduling state necessary to support operation of the endpoint, and once
- // it returns ipcz may immediately begin making Transmit() calls on
- // `driver_transport`.
- //
- // Any return value other than IPCZ_RESULT_OK indicates an error, and the
- // endpoint will be dropped by ipcz. Otherwise the endpoint may be used
- // immediately to accept or submit data, and it should continue to operate
- // until ipcz calls Close() on `driver_transport`.
- //
- // Note that `activity_handler` invocations MUST be mutually exclusive,
- // because transmissions from ipcz are expected to arrive and be processed
- // strictly in-order.
- //
- // The driver may elicit forced destruction of itself by calling
- // `activity_handler` with the flag IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED.
- IpczResult(IPCZ_API* ActivateTransport)(
- IpczDriverHandle driver_transport, // in
- IpczHandle transport, // in
- IpczTransportActivityHandler activity_handler, // in
- uint32_t flags, // in
- const void* options); // in
- // Called by ipcz to deactivate a transport. The driver does not need to
- // complete deactivation synchronously, but it must begin to deactivate the
- // transport and must invoke the transport's activity handler one final time
- // with IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED once finished. Beyond that point,
- // the activity handler must no longer be invoked for that transport.
- //
- // Note that even after deactivatoin, ipcz may continue to call into the
- // transport until it's closed with an explicit call to the driver's Close()
- // by ipcz.
- IpczResult(IPCZ_API* DeactivateTransport)(
- IpczDriverHandle driver_transport, // in
- uint32_t flags, // in
- const void* options); // in
- // Called by ipcz to delegate transmission of data and driver handles over the
- // identified transport endpoint. If the driver cannot fulfill the request,
- // it must return a result other than IPCZ_RESULT_OK, and this will cause the
- // transport's connection to be severed.
- //
- // Note that any driver handles in `driver_handles` were obtained by ipcz from
- // the driver itself, by some prior call to the driver's own Serialize()
- // function. These handles are therefore expected to be directly transmissible
- // by the driver alongside any data in `data`.
- //
- // The net result of this transmission should be an activity handler
- // invocation on the corresponding remote transport by the driver on its node.
- // It is the driver's responsibility to get any data and handles to the other
- // transport, and to ensure that all transmissions from transport end up
- // invoking the activity handler on the peer transport in the same order they
- // were transmitted.
- //
- // If ipcz only wants to wake the peer node rather than transmit data or
- // handles, `num_bytes` and `num_driver_handles` may both be zero.
- IpczResult(IPCZ_API* Transmit)(IpczDriverHandle driver_transport, // in
- const void* data, // in
- size_t num_bytes, // in
- const IpczDriverHandle* driver_handles, // in
- size_t num_driver_handles, // in
- uint32_t flags, // in
- const void* options); // in
- // Allocates a shared memory region and returns a driver handle in
- // `driver_memory` which can be used to reference it in other calls to the
- // driver.
- IpczResult(IPCZ_API* AllocateSharedMemory)(
- size_t num_bytes, // in
- uint32_t flags, // in
- const void* options, // in
- IpczDriverHandle* driver_memory); // out
- // Returns information about the shared memory region identified by
- // `driver_memory`.
- IpczResult(IPCZ_API* GetSharedMemoryInfo)(
- IpczDriverHandle driver_memory, // in
- uint32_t flags, // in
- const void* options, // in
- struct IpczSharedMemoryInfo* info); // out
- // Duplicates a shared memory region handle into a new distinct handle
- // referencing the same underlying region.
- IpczResult(IPCZ_API* DuplicateSharedMemory)(
- IpczDriverHandle driver_memory, // in
- uint32_t flags, // in
- const void* options, // in
- IpczDriverHandle* new_driver_memory); // out
- // Maps a shared memory region identified by `driver_memory` and returns its
- // mapped address in `address` on success and a driver handle in
- // `driver_mapping` which can be passed to the driver's Close() to unmap the
- // region later.
- //
- // Note that the lifetime of `driver_mapping` should be independent from that
- // of `driver_memory`. That is, if `driver_memory` is closed immediately after
- // this call succeeds, the returned mapping must still remain valid until the
- // mapping itself is closed.
- IpczResult(IPCZ_API* MapSharedMemory)(
- IpczDriverHandle driver_memory, // in
- uint32_t flags, // in
- const void* options, // in
- void** address, // out
- IpczDriverHandle* driver_mapping); // out
- // Generates `num_bytes` bytes of random data to fill `buffer`.
- IpczResult(IPCZ_API* GenerateRandomBytes)(size_t num_bytes, // in
- uint32_t flags, // in
- const void* options, // in
- void* buffer); // out
- };
- #if defined(__cplusplus)
- } // extern "C"
- #endif
- // See CreateNode() and the IPCZ_CREATE_NODE_* flag descriptions below.
- typedef uint32_t IpczCreateNodeFlags;
- // Indicates that the created node will serve as the broker in its cluster.
- //
- // Brokers are expected to live in relatively trusted processes -- not
- // necessarily elevated in privilege but also generally not restricted by
- // sandbox constraints and not prone to processing risky, untrusted data -- as
- // they're responsible for helping other nodes establish direct lines of
- // communication as well as in some cases relaying data and driver handles
- // between lesser-privileged nodes.
- //
- // Broker nodes do not expose any additional ipcz APIs or require much other
- // special care on the part of the application**, but every cluster of connected
- // nodes must have a node designated as the broker. Typically this is the first
- // node created by an application's main process or a system-wide service
- // coordinator, and all other nodes are created in processes spawned by that one
- // or in processes which otherwise trust it.
- //
- // ** See notes on Close() regarding destruction of broker nodes.
- #define IPCZ_CREATE_NODE_AS_BROKER IPCZ_FLAG_BIT(0)
- // See ConnectNode() and the IPCZ_CONNECT_NODE_* flag descriptions below.
- typedef uint32_t IpczConnectNodeFlags;
- // Indicates that the remote node for this connection is expected to be a broker
- // node, and it will be treated as such. Do not use this flag when connecting to
- // any untrusted process.
- #define IPCZ_CONNECT_NODE_TO_BROKER IPCZ_FLAG_BIT(0)
- // Indicates that the remote node for this connection is expected not to be a
- // broker, but to already have a link to a broker; and that the calling node
- // wishes to inherit the remote node's broker as well. This flag must only be
- // used when connecting to a node the caller trusts. The calling node must not
- // already have an established broker from a previous ConnectNode() call. The
- // remote node must specify IPCZ_CONNECT_NODE_SHARE_BROKER as well.
- #define IPCZ_CONNECT_NODE_INHERIT_BROKER IPCZ_FLAG_BIT(1)
- // Indicates that the calling node already has a broker, and that this broker
- // will be inherited by the remote node. The remote node must also specify
- // IPCZ_CONNECT_NODE_INHERIT_BROKER in its corresponding ConnectNode() call.
- #define IPCZ_CONNECT_NODE_SHARE_BROKER IPCZ_FLAG_BIT(2)
- // ipcz may periodically allocate shared memory regions to facilitate
- // communication between two nodes. In many runtime environments, even within
- // a security sandbox, the driver can do do this safely and directly by
- // interfacing with the OS. In some environments however, direct allocation is
- // not possible. In such cases a node must delegate this responsibility to some
- // other trusted node in the system, typically the broker node.
- //
- // Specifying this flag ensures that all shared memory allocation elicited by
- // the connecting node will be delegated to the connectee.
- #define IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE IPCZ_FLAG_BIT(3)
- // Optional limits provided by IpczPutOptions for Put() or IpczBeginPutOptions
- // for BeginPut().
- struct IPCZ_ALIGN(8) IpczPutLimits {
- // The exact size of this structure in bytes. Must be set accurately before
- // passing the structure to any API functions.
- size_t size;
- // Specifies the maximum number of unread parcels to allow in a portal's
- // queue. If a Put() or BeginPut() call specifying this limit would cause the
- // receiver's number of number of queued unread parcels to exceed this value,
- // the call will fail with IPCZ_RESULT_RESOURCE_EXHAUSTED.
- size_t max_queued_parcels;
- // Specifies the maximum number of data bytes to allow in a portal's queue.
- // If a Put() or BeginPut() call specifying this limit would cause the number
- // of data bytes across all queued unread parcels to exceed this value, the
- // call will fail with IPCZ_RESULT_RESOURCE_EXHAUSTED.
- size_t max_queued_bytes;
- };
- // Options given to Put() to modify its default behavior.
- struct IPCZ_ALIGN(8) IpczPutOptions {
- // The exact size of this structure in bytes. Must be set accurately before
- // passing the structure to Put().
- size_t size;
- // Optional limits to apply when determining if the Put() should be completed.
- const struct IpczPutLimits* limits;
- };
- // See BeginPut() and the IPCZ_BEGIN_PUT_* flags described below.
- typedef uint32_t IpczBeginPutFlags;
- // Indicates that the caller is willing to produce less data than originally
- // requested by their `*num_bytes` argument to BeginPut(). If the implementation
- // would prefer a smaller chunk of data or if the requested size would exceed
- // limits specified in the call's corresponding IpczPutLimits, passing this flag
- // may allow the call to succeed while returning a smaller acceptable value in
- // `*num_bytes`, rather than simply failing the call with
- // IPCZ_RESULT_RESOURCE_EXHAUSTED.
- #define IPCZ_BEGIN_PUT_ALLOW_PARTIAL IPCZ_FLAG_BIT(0)
- // Options given to BeginPut() to modify its default behavior.
- struct IPCZ_ALIGN(8) IpczBeginPutOptions {
- // The exact size of this structure in bytes. Must be set accurately before
- // passing the structure to BeginPut().
- size_t size;
- // Optional limits to apply when determining if the BeginPut() should be
- // completed.
- const struct IpczPutLimits* limits;
- };
- // See EndPut() and the IPCZ_END_PUT_* flags described below.
- typedef uint32_t IpczEndPutFlags;
- // If this flag is given to EndPut(), any in-progress two-phase put operation is
- // aborted without committing a parcel to the portal.
- #define IPCZ_END_PUT_ABORT IPCZ_FLAG_BIT(0)
- // See Get() and the IPCZ_GET_* flag descriptions below.
- typedef uint32_t IpczGetFlags;
- // When given to Get(), this flag indicates that the caller is willing to accept
- // a partial retrieval of the next available parcel. This means that in
- // situations where Get() would normally return IPCZ_RESULT_RESOURCE_EXHAUSTED,
- // it will instead return IPCZ_RESULT_OK with as much data and handles as the
- // caller indicated they could accept.
- #define IPCZ_GET_PARTIAL IPCZ_FLAG_BIT(0)
- // See EndGet() and the IPCZ_END_GET_* flag descriptions below.
- typedef uint32_t IpczEndGetFlags;
- // If this flag is given to EndGet(), any in-progress two-phase get operation is
- // aborted without consuming any data from the portal.
- #define IPCZ_END_GET_ABORT IPCZ_FLAG_BIT(0)
- // See Unbox() and the IPCZ_UNBOX_* flags described below.
- typedef uint32_t IpczUnboxFlags;
- // If set, the box is not consumed and the driver handle returned is not removed
- // from the box.
- #define IPCZ_UNBOX_PEEK IPCZ_FLAG_BIT(0)
- // Flags given by the `flags` field in IpczPortalStatus.
- typedef uint32_t IpczPortalStatusFlags;
- // Indicates that the opposite portal is closed. Subsequent put operations on
- // this portal will always fail with IPCZ_RESULT_NOT_FOUND. If there are not
- // currently any unretrieved parcels in the portal either, subsequent get
- // operations will also fail with the same error.
- #define IPCZ_PORTAL_STATUS_PEER_CLOSED IPCZ_FLAG_BIT(0)
- // Indicates that the opposite portal is closed AND no more parcels can be
- // expected to arrive from it. If this bit is set on a portal's status, the
- // portal is essentially useless. Such portals no longer support Put() or
- // Get() operations, and those operations will subsequently always return
- // IPCZ_RESULT_NOT_FOUND.
- #define IPCZ_PORTAL_STATUS_DEAD IPCZ_FLAG_BIT(1)
- // Information returned by QueryPortalStatus() or provided to
- // IpczTrapEventHandlers when a trap's conditions are met on a portal.
- struct IPCZ_ALIGN(8) IpczPortalStatus {
- // The exact size of this structure in bytes. Must be set accurately before
- // passing the structure to any functions.
- size_t size;
- // Flags. See the IPCZ_PORTAL_STATUS_* flags described above for the possible
- // flags combined in this value.
- IpczPortalStatusFlags flags;
- // The number of unretrieved parcels queued on this portal.
- size_t num_local_parcels;
- // The number of unretrieved bytes (across all unretrieved parcels) queued on
- // this portal.
- size_t num_local_bytes;
- // The number of unretrieved parcels queued on the opposite portal.
- size_t num_remote_parcels;
- // The number of unretrieved bytes (across all unretrieved parcels) queued on
- // the opposite portal.
- size_t num_remote_bytes;
- };
- // Flags given to IpczTrapConditions to indicate which types of conditions a
- // trap should observe.
- //
- // Note that each type of condition may be considered edge-triggered or
- // level-triggered. An edge-triggered condition is one which is only
- // observable momentarily in response to a state change, while a level-triggered
- // condition is continuously observable as long as some constraint about a
- // portal's state is met.
- //
- // Level-triggered conditions can cause a Trap() attempt to fail if they're
- // already satisfied when attempting to install a trap to monitor them.
- typedef uint32_t IpczTrapConditionFlags;
- // Triggers a trap event when the trap's portal is itself closed. This condition
- // is always observed even if not explicitly set in the IpczTrapConditions given
- // to the Trap() call. If a portal is closed while a trap is installed on it,
- // an event will fire for the trap with this condition flag set. This condition
- // is effectively edge-triggered, because as soon as it becomes true, any
- // observing trap as well as its observed subject cease to exist.
- #define IPCZ_TRAP_REMOVED IPCZ_FLAG_BIT(0)
- // Triggers a trap event whenever the opposite portal is closed. Typically
- // applications are interested in the more specific IPCZ_TRAP_DEAD.
- // Level-triggered.
- #define IPCZ_TRAP_PEER_CLOSED IPCZ_FLAG_BIT(1)
- // Triggers a trap event whenever there are no more parcels available to
- // retrieve from this portal AND the opposite portal is closed. This means the
- // portal will never again have parcels to retrieve and is effectively useless.
- // Level-triggered.
- #define IPCZ_TRAP_DEAD IPCZ_FLAG_BIT(2)
- // Triggers a trap event whenever the number of parcels queued for retrieval by
- // this portal exceeds the threshold given by `min_local_parcels` in
- // IpczTrapConditions. Level-triggered.
- #define IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS IPCZ_FLAG_BIT(3)
- // Triggers a trap event whenever the number of bytes queued for retrieval by
- // this portal exceeds the threshold given by `min_local_bytes` in
- // IpczTrapConditions. Level-triggered.
- #define IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES IPCZ_FLAG_BIT(4)
- // Triggers a trap event whenever the number of parcels queued for retrieval on
- // the opposite portal drops below the threshold given by `max_remote_parcels`
- // IpczTrapConditions. Level-triggered.
- #define IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS IPCZ_FLAG_BIT(5)
- // Triggers a trap event whenever the number of bytes queued for retrieval on
- // the opposite portal drops below the threshold given by `max_remote_bytes` in
- // IpczTrapConditions. Level-triggered.
- #define IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES IPCZ_FLAG_BIT(6)
- // Triggers a trap event whenever the number of locally available parcels
- // increases by any amount. Edge-triggered.
- #define IPCZ_TRAP_NEW_LOCAL_PARCEL IPCZ_FLAG_BIT(7)
- // Triggers a trap event whenever the number of queued remote parcels decreases
- // by any amount. Edge-triggered.
- #define IPCZ_TRAP_CONSUMED_REMOTE_PARCEL IPCZ_FLAG_BIT(8)
- // A structure describing portal conditions necessary to trigger a trap and
- // invoke its event handler.
- struct IPCZ_ALIGN(8) IpczTrapConditions {
- // The exact size of this structure in bytes. Must be set accurately before
- // passing the structure to Trap().
- size_t size;
- // See the IPCZ_TRAP_* flags described above.
- IpczTrapConditionFlags flags;
- // See IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS. If that flag is not set in `flags`,
- // this field is ignord.
- size_t min_local_parcels;
- // See IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES. If that flag is not set in `flags`,
- // this field is ignored.
- size_t min_local_bytes;
- // See IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS. If that flag is not set in `flags`,
- // this field is ignored.
- size_t max_remote_parcels;
- // See IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES. If that flag is not set in `flags`,
- // this field is ignored.
- size_t max_remote_bytes;
- };
- // Structure passed to each IpczTrapEventHandler invocation with details about
- // the event.
- struct IPCZ_ALIGN(8) IpczTrapEvent {
- // The size of this structure in bytes. Populated by ipcz to indicate which
- // version is being provided to the handler.
- size_t size;
- // The context value that was given to Trap() when installing the trap that
- // fired this event.
- uintptr_t context;
- // Flags indicating which condition(s) triggered this event.
- IpczTrapConditionFlags condition_flags;
- // The current status of the portal which triggered this event. This address
- // is only valid through the extent of the event handler invocation.
- const struct IpczPortalStatus* status;
- };
- // An application-defined function to be invoked by a trap when its observed
- // conditions are satisfied on the monitored portal.
- typedef void(IPCZ_API* IpczTrapEventHandler)(const struct IpczTrapEvent* event);
- #if defined(__cplusplus)
- extern "C" {
- #endif
- // Table of API functions defined by ipcz. Instances of this structure may be
- // populated by passing them to an implementation of IpczGetAPIFn.
- //
- // Note that all functions follow a consistent parameter ordering:
- //
- // 1. Object handle (node or portal) if applicable
- // 2. Function-specific strict input values
- // 3. Flags - possibly untyped and unused
- // 4. Options struct - possibly untyped and unused
- // 5. Function-specific in/out values
- // 6. Function-specific strict output values
- //
- // The rationale behind this convention is generally to have order flow from
- // input to output. Flags are inputs, and options provide an extension point for
- // future versions of these APIs; as such they skirt the boundary between strict
- // input values and in/out values.
- //
- // The order and signature (ABI) of functions defined here must never change,
- // but new functions may be added to the end.
- struct IPCZ_ALIGN(8) IpczAPI {
- // The exact size of this structure in bytes. Must be set accurately by the
- // application before passing the structure to an implementation of
- // IpczGetAPIFn.
- size_t size;
- // Releases the object identified by `handle`. If it's a portal, the portal is
- // closed. If it's a node, the node is destroyed. If it's a wrapped driver
- // object, the object is released via the driver API's Close().
- //
- // This function is NOT thread-safe. It is the application's responsibility to
- // ensure that no other threads are performing other operations on `handle`
- // concurrently with this call or any time thereafter.
- //
- // Note that while closure is itself a (non-blocking) synchronous operation,
- // closure of various objects may have asynchronous side effects. For example,
- // closing a portal might asynchronously trigger a trap event on the portal's
- // remote peer.
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // NOTE: If `handle` is a broker node in its cluster of connected nodes,
- // certain operations across the cluster -- such as driver object transmission
- // through portals or portal transference in general -- may begin to fail
- // spontaneously once destruction is complete.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if `handle` referred to a valid object and was
- // successfully closed by this operation.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `handle` is invalid.
- IpczResult(IPCZ_API* Close)(IpczHandle handle, // in
- uint32_t flags, // in
- const void* options); // in
- // Initializes a new ipcz node. Applications typically need only one node in
- // each communicating process, but it's OK to create more. Practical use cases
- // for multiple nodes per process may include various testing scenarios, and
- // any situation where simulating a multiprocess environment is useful.
- //
- // All other ipcz calls are scoped to a specific node, or to a more specific
- // object which is itself scoped to a specific node.
- //
- // `driver` is the driver to use when coordinating internode communication.
- // Nodes which will be interconnected must use the same or compatible driver
- // implementations.
- //
- // `driver_node` is a driver-side handle to assign to the node throughout its
- // lifetime. This handle provides the driver with additional context when ipcz
- // makes driver API calls pertaining to a specific node. May be
- // IPCZ_INVALID_DRIVER_HANDLE if not used by the driver.
- //
- // If `flags` contains IPCZ_CREATE_NODE_AS_BROKER then the node will act as
- // the broker in its cluster of connected nodes. See details on that flag
- // description above.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if a new node was created. In this case, `*node` is
- // populated with a valid node handle upon return.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `node` is null, or `driver` is null or
- // invalid.
- //
- // IPCZ_RESULT_UNIMPLEMENTED if some condition of the runtime environment
- // or architecture-specific details of the ipcz build would prevent it
- // from operating correctly. For example, the is returned if ipcz was
- // built against a std::atomic implementation which does not provide
- // lock-free 32-bit and 64-bit atomics.
- IpczResult(IPCZ_API* CreateNode)(const struct IpczDriver* driver, // in
- IpczDriverHandle driver_node, // in
- IpczCreateNodeFlags flags, // in
- const void* options, // in
- IpczHandle* node); // out
- // Connects `node` to another node in the system using an application-provided
- // driver transport handle in `driver_transport` for communication. If this
- // call will succeed, ipcz will call back into the driver to activate this
- // transport via ActivateTransport() before returning.
- //
- // The application is responsible for delivering the other endpoint of the
- // transport to whatever other node will use it with its own corresponding
- // ConnectNode() call.
- //
- // The calling node opens a number of initial portals (given by
- // `num_initial_portals`) linked to corresponding initial portals on the
- // remote node as soon as a two-way connection is fully established.
- //
- // Establishment of this connection is typically asynchronous, but this
- // depends on the driver implementation. In any case, the initial portals are
- // created and returned synchronously and can be used immediately by the
- // application. If the remote node issues a corresponding ConnectNode() call
- // with a smaller `num_initial_portals`, the excess portals created by this
- // node will behave as if their peer has been closed. On the other hand if the
- // remote node gives a larger `num_initial_portals`, then its own excess
- // portals will behave as if their peer has been closed.
- //
- //
- // If IPCZ_CONNECT_NODE_TO_BROKER is given in `flags`, the remote node must
- // be a broker node, and the calling node will treat it as such. If the
- // calling node is also a broker, the brokers' respective networks will be
- // effectively merged as long as both brokers remain alive: nodes in one
- // network will be able to discover and communicate directly with nodes in the
- // other network. Note that when two networks are merged, each broker remains
- // as the only broker within its own network; but brokers share enough
- // information to allow for discovery and interconnection of nodes between
- // networks.
- //
- // Conversely if IPCZ_CONNECT_NODE_TO_BROKER is *not* given and neither the
- // local nor remote nodes is a broker, one of the two nodes MUST NOT have a
- // broker yet and must specify IPCZ_CONNECT_NODE_INHERIT_BROKER in its
- // ConnectNode() call. The other node MUST have a broker already and it must
- // specify IPCZ_CONNECT_NODE_SHARE_BROKER in its own corresponding
- // ConnectNode() call.
- //
- // If IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE is given in `flags`, the
- // calling node delegates all ipcz internal shared memory allocation
- // operations to the remote node. This flag should only be used when the
- // calling node is operating in a restricted environment where direct shared
- // memory allocation is not possible.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if all arguments were valid and connection was initiated.
- // `num_initial_portals` portal handles are populated in
- // `initial_portals`. These may be used immediately by the application.
- //
- // Note that because the underlying connection may be established
- // asynchronously (depending on the driver implementation), this
- // operation may still fail after returning this value. If this
- // happens, all of the returned initial portals will behave as if their
- // peer has been closed.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `node` is invalid, `num_initial_portals`
- // is zero, `initial_portals` is null, or `flags` specifies one or more
- // flags which are invalid for `node` or invalid when combined.
- //
- // IPCZ_RESULT_OUT_OF_RANGE if `num_initial_portals` is larger than the
- // ipcz implementation allows. There is no hard limit specified, but
- // any ipcz implementation must support at least 8 initial portals.
- IpczResult(IPCZ_API* ConnectNode)(IpczHandle node, // in
- IpczDriverHandle driver_transport, // in
- size_t num_initial_portals, // in
- IpczConnectNodeFlags flags, // in
- const void* options, // in
- IpczHandle* initial_portals); // out
- // Opens two new portals which exist as each other's opposite.
- //
- // Data and handles can be put in a portal with put operations (see Put(),
- // BeginPut(), EndPut()). Anything placed into a portal can be retrieved in
- // the same order by get operations (Get(), BeginGet(), EndGet()) on the
- // opposite portal.
- //
- // To open portals which span two different nodes at creation time, see
- // ConnectNode().
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if portal creation was successful. `*portal0` and
- // `*portal1` are each populated with opaque portal handles which
- // identify the new pair of portals. The new portals are each other's
- // opposite and are entangled until one of them is closed.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `node` is invalid, or if either
- // `portal0` or `portal1` is null.
- IpczResult(IPCZ_API* OpenPortals)(IpczHandle node, // in
- uint32_t flags, // in
- const void* options, // in
- IpczHandle* portal0, // out
- IpczHandle* portal1); // out
- // Merges two portals into each other, effectively destroying both while
- // linking their respective peer portals with each other. A portal cannot
- // merge with its own peer, and a portal cannot be merged into another if one
- // or more parcels have already been put into or taken out of either of them.
- // There are however no restrictions on what can be done to the portal's peer
- // prior to merging the portal with another.
- //
- // If we have two portal pairs:
- //
- // A ---- B and C ---- D
- //
- // some parcels are placed into A, and some parcels are placed into D, and
- // then we merge B with C, the net result will be a single portal pair:
- //
- // A ---- D
- //
- // All past and future parcels placed into A will arrive at D, and vice versa.
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the two portals were merged successfully. Neither
- // handle is valid past this point. Parcels now travel between the
- // merged portals' respective peers, including any parcels that were
- // in flight or queued at the time of this merge.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `first` or `second` is invalid, if
- // `first` and `second` are each others' peer, or `first` and `second`
- // refer to the same portal.
- //
- // IPCZ_RESULT_FAILED_PRECONDITION if either `first` or `second` has
- // already had one or more parcels put into or gotten out of them.
- IpczResult(IPCZ_API* MergePortals)(IpczHandle first, // in
- IpczHandle second, // in
- uint32_t flags, // in
- const void* options); // out
- // Queries specific details regarding the status of a portal, such as the
- // number of unread parcels or data bytes available on the portal or its
- // opposite, or whether the opposite portal has already been closed.
- //
- // Note that because the portal's status is inherently dynamic and may be
- // modified at any time by any thread in any process with a handle to either
- // the portal or its opposite, the information returned in `status` may be
- // stale by the time a successful QueryPortalStatus() call returns.
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the requested query was completed successfully.
- // `status` is populated with details.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT `portal` is invalid. `status` is null or
- // invalid.
- IpczResult(IPCZ_API* QueryPortalStatus)(
- IpczHandle portal, // in
- uint32_t flags, // in
- const void* options, // in
- struct IpczPortalStatus* status); // out
- // Puts any combination of data and handles into the portal identified by
- // `portal`. Everything put into a portal can be retrieved in the same order
- // by a corresponding get operation on the opposite portal. Depending on the
- // driver and the state of the relevant portals, the data and handles may
- // be delivered and retreivable immediately by the remote portal, or they may
- // be delivered asynchronously.
- //
- // `flags` is unused and must be IPCZ_NO_FLAGS.
- //
- // `options` may be null.
- //
- // If this call fails (returning anything other than IPCZ_RESULT_OK), any
- // provided handles remain property of the caller. If it succeeds, their
- // ownership is assumed by ipcz.
- //
- // Data to be submitted is read directly from the address given by the `data`
- // argument, and `num_bytes` specifies how many bytes of data to copy from
- // there.
- //
- // Callers may wish to request a view directly into portal memory for direct
- // writing. In such cases, a two-phase put operation can be used instead, by
- // calling BeginPut() and EndPut() as defined below.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the provided data and handles were successfull placed
- // into the portal as a new parcel.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `data` is null but
- // `num_bytes` is non-zero, `handles` is null but `num_handles` is
- // non-zero, `options` is non-null but invalid, one of the handles in
- // `handles` is equal to `portal` or its (local) opposite if
- // applicable, or if any handle in `handles` is invalid or not
- // serializable.
- //
- // IPCZ_RESULT_RESOURCE_EXHAUSTED if `options->limits` is non-null and at
- // least one of the specified limits would be violated by the
- // successful completion of this call.
- //
- // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
- // already been closed and anything put into this portal would be lost.
- IpczResult(IPCZ_API* Put)(IpczHandle portal, // in
- const void* data, // in
- size_t num_bytes, // in
- const IpczHandle* handles, // in
- size_t num_handles, // in
- uint32_t flags, // in
- const struct IpczPutOptions* options); // in
- // Begins a two-phase put operation on `portal`. While a two-phase put
- // operation is in progress on a portal, any other BeginPut() call on the same
- // portal will fail with IPCZ_RESULT_ALREADY_EXISTS.
- //
- // Unlike a plain Put() call, two-phase put operations allow the application
- // to write directly into portal memory, potentially reducing memory access
- // costs by eliminating redundant copying and caching.
- //
- // The input value of `*num_bytes` tells ipcz how much data the caller would
- // like to place into the portal.
- //
- // Limits provided to BeginPut() elicit similar behavior to Put(), with the
- // exception that `flags` may specify IPCZ_BEGIN_PUT_ALLOW_PARTIAL to allow
- // BeginPut() to succeed even the caller's suggested value of
- // `*num_bytes` would cause the portal to exceed the maximum queued byte limit
- // given by `options->limits`. In that case BeginPut() may update `*num_bytes`
- // to reflect the remaining capacity of the portal, allowing the caller to
- // commit at least some portion of their data with EndPut().
- //
- // Handles for two-phase puts are only provided when finalizing the operation
- // with EndPut().
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the two-phase put operation has been successfully
- // initiated. This operation must be completed with EndPut() before any
- // further Put() or BeginPut() calls are allowed on `portal`. `*data`
- // is set to the address of a portal buffer into which the application
- // may copy its data, and `*num_bytes` is updated to reflect the
- // capacity of that buffer, which may be greater than (or less than, if
- // and only if IPCZ_BEGIN_PUT_ALLOW_PARTIAL was set in `flags`) the
- // capacity requested by the input value of `*num_bytes`.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `*num_bytes` is
- // non-zero but `data` is null, or options is non-null and invalid.
- //
- // IPCZ_RESULT_RESOURCE_EXHAUSTED if completing the put with the number of
- // bytes specified by `*num_bytes` would cause the portal to exceed the
- // queued parcel limit or (if IPCZ_BEGIN_PUT_ALLOW_PARTIAL is not
- // specified in `flags`) data byte limit specified by
- // `options->limits`.
- //
- // IPCZ_RESULT_ALREADY_EXISTS if there is already a two-phase put operation
- // in progress on `portal`.
- //
- // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
- // already been closed and anything put into this portal would be lost.
- IpczResult(IPCZ_API* BeginPut)(
- IpczHandle portal, // in
- IpczBeginPutFlags flags, // in
- const struct IpczBeginPutOptions* options, // in
- size_t* num_bytes, // out
- void** data); // out
- // Ends the two-phase put operation started by the most recent successful call
- // to BeginPut() on `portal`.
- //
- // `num_bytes_produced` specifies the number of bytes actually written into
- // the buffer that was returned from the original BeginPut() call.
- //
- // Usage of `handles` and `num_handles` is identical to Put().
- //
- // If this call fails (returning anything other than IPCZ_RESULT_OK), any
- // provided handles remain property of the caller. If it succeeds, their
- // ownership is assumed by ipcz.
- //
- // If IPCZ_END_PUT_ABORT is given in `flags` and there is a two-phase put
- // operation in progress on `portal`, all other arguments are ignored and the
- // pending two-phase put operation is cancelled without committing a new
- // parcel to the portal.
- //
- // If EndPut() fails for any reason other than
- // IPCZ_RESULT_FAILED_PRECONDITION, the two-phase put operation remains in
- // progress, and EndPut() must be called again to abort the operation or
- // attempt completion with different arguments.
- //
- // `options` is unused and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the two-phase operation was successfully completed or
- // aborted. If not aborted all data and handles were committed to a new
- // parcel enqueued for retrieval by the opposite portal.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `num_handles` is
- // non-zero but `handles` is null, `num_bytes_produced` is larger than
- // the capacity of the buffer originally returned by BeginPut(), or any
- // handle in `handles` is invalid or not serializable.
- //
- // IPCZ_RESULT_FAILED_PRECONDITION if there was no two-phase put operation
- // in progress on `portal`.
- //
- // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
- // already been closed and anything put into this portal would be lost.
- IpczResult(IPCZ_API* EndPut)(IpczHandle portal, // in
- size_t num_bytes_produced, // in
- const IpczHandle* handles, // in
- size_t num_handles, // in
- IpczEndPutFlags flags, // in
- const void* options); // in
- // Retrieves some combination of data and handles from a portal, as placed by
- // a prior put operation on the opposite portal.
- //
- // On input, the values pointed to by `num_bytes` and `num_handles` must
- // specify the capacity of each corresponding buffer argument. A null pointer
- // implies zero capacity. It is an error to specify non-zero capacity if the
- // corresponding buffer (`data` or `handles`) is null.
- //
- // Normally the data consumed by this call is copied directly to the address
- // given by the `data` argument, and `*num_bytes` specifies how many bytes of
- // storage are available there. If an application wishes to read directly
- // from portal memory instead, a two-phase get operation can be used by
- // calling BeginGet() and EndGet() as defined below.
- //
- // Note that if the caller does not provide enough storage capacity for a
- // complete parcel and does not specify IPCZ_GET_PARTIAL in `flags`, this
- // returns IPCZ_RESULT_RESOURCE_EXHAUSTED and outputs the actual capacity
- // required for the message without copying any of its contents. See details
- // of that return value below.
- //
- // If IPCZ_GET_PARTIAL is specified, the call succeeds as long as a parcel is
- // available, and the caller retrieves as much data and handles as their
- // expressed capacity will allow. In this case, the in/out capacity arguments
- // (`num_bytes` and `num_handles`) are still updated as specified in the
- // IPCZ_RESULT_OK details below.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if there was a parcel available in the portal's queue and
- // its data and handles were able to be copied into the caller's
- // provided buffers. In this case values pointed to by `num_bytes` and
- // `num_handles` (for each one that is non-null) are updated to reflect
- // what was actually consumed. Note that the caller assumes ownership
- // of all returned handles.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `data` is null but
- // `*num_bytes` is non-zero, or `handles` is null but `*num_handles` is
- // non-zero.
- //
- // IPCZ_RESULT_RESOURCE_EXHAUSTED if the next available parcel would exceed
- // the caller's specified capacity for either data bytes or handles,
- // and IPCZ_GET_PARTIAL was not specified in `flags`. In this case, any
- // non-null size pointer is updated to convey the minimum capacity that
- // would have been required for an otherwise identical Get() call to
- // have succeeded. Callers observing this result may wish to allocate
- // storage accordingly and retry with updated parameters.
- //
- // IPCZ_RESULT_UNAVAILABLE if the portal's parcel queue is currently empty.
- // In this case callers should wait before attempting to get anything
- // from the same portal again.
- //
- // IPCZ_RESULT_NOT_FOUND if there are no more parcels in the portal's queue
- // AND the opposite portal is known to be closed. If this result is
- // returned, no parcels can ever be read from this portal again.
- //
- // IPCZ_RESULT_ALREADY_EXISTS if there is a two-phase get operation in
- // progress on `portal`.
- IpczResult(IPCZ_API* Get)(IpczHandle portal, // in
- IpczGetFlags flags, // in
- const void* options, // in
- void* data, // out
- size_t* num_bytes, // in/out
- IpczHandle* handles, // out
- size_t* num_handles); // in/out
- // Begins a two-phase get operation on `portal` to retrieve data and handles.
- // While a two-phase get operation is in progress on a portal, all other get
- // operations on the same portal will fail with IPCZ_RESULT_ALREADY_EXISTS.
- //
- // Unlike a plain Get() call, two-phase get operations allow the application
- // to read directly from portal memory, potentially reducing memory access
- // costs by eliminating redundant copying and caching.
- //
- // If `data` or `num_bytes` is null and the available parcel has at least one
- // byte of data, or if there are handles present but `num_handles` is null,
- // this returns IPCZ_RESULT_RESOURCE_EXHAUSTED.
- //
- // Otherwise a successful BeginGet() updates values pointed to by `data`,
- // `num_bytes`, and `num_handles` to convey the parcel's data storage and
- // capacity as well as the capacity required to read out any handles.
- //
- // NOTE: When performing two-phase get operations, callers should be mindful
- // of time-of-check/time-of-use (TOCTOU) vulnerabilities. Exposed parcel
- // memory may be shared with (and writable in) the process which placed the
- // parcel into the portal, and that process may not be trustworthy. In such
- // cases, applications should be careful to copy the data out before
- // validating and using it.
- //
- // `flags` is ignored and must be IPCZ_NO_FLAGS.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the two-phase get was successfully initiated. In this
- // case both `*data` and `*num_bytes` are updated (if `data` and
- // `num_bytes` were non-null) to describe the portal memory from which
- // the application is free to read parcel data. If `num_handles` is
- // is non-null, the value pointed to is updated to reflect the number
- // of handles available to retrieve.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid.
- //
- // IPCZ_RESULT_RESOURCE_EXHAUSTED if the next available parcel has at least
- // one data byte but `data` or `num_bytes` is null; or if the parcel
- // has any handles but `num_handles` null.
- //
- // IPCZ_RESULT_UNAVAILABLE if the portal's parcel queue is currently empty.
- // In this case callers should wait before attempting to get anything
- // from the same portal again.
- //
- // IPCZ_RESULT_NOT_FOUND if there are no more parcels in the portal's queue
- // AND the opposite portal is known to be closed. In this case, no get
- // operation can ever succeed again on this portal.
- //
- // IPCZ_RESULT_ALREADY_EXISTS if there is already a two-phase get operation
- // in progress on `portal`.
- IpczResult(IPCZ_API* BeginGet)(IpczHandle portal, // in
- uint32_t flags, // in
- const void* options, // in
- const void** data, // out
- size_t* num_bytes, // out
- size_t* num_handles); // out
- // Ends the two-phase get operation started by the most recent successful call
- // to BeginGet() on `portal`.
- //
- // `num_bytes_consumed` specifies the number of bytes actually read from the
- // buffer that was returned from the original BeginGet() call. `num_handles`
- // specifies the capacity of `handles` and must be no larger than the
- // capacity indicated by the corresponding output from BeginGet().
- //
- // If IPCZ_END_GET_ABORT is given in `flags` and there is a two-phase get
- // operation in progress on `portal`, all other arguments are ignored and the
- // pending operation is cancelled without consuming any data from the portal.
- //
- // `options` is unused and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the two-phase operation was successfully completed or
- // aborted. Note that if the frontmost parcel wasn't fully consumed by
- // the caller, it will remain in queue with the rest of its data intact
- // for a subsequent get operation to retrieve. Exactly `num_handles`
- // handles will be copied into `handles`.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, or if `num_handles`
- // is non-zero but `handles` is null.
- //
- // IPCZ_RESULT_OUT_OF_RANGE if either `num_bytes_consumed` or `num_handles`
- // is larger than the capacity returned by BeginGet().
- //
- // IPCZ_RESULT_FAILED_PRECONDITION if there was no two-phase get operation
- // in progress on `portal`.
- IpczResult(IPCZ_API* EndGet)(IpczHandle portal, // in
- size_t num_bytes_consumed, // in
- size_t num_handles, // in
- IpczEndGetFlags flags, // in
- const void* options, // in
- IpczHandle* handles); // out
- // Attempts to install a trap to catch interesting changes to a portal's
- // state. The condition(s) to observe are specified in `conditions`.
- // Regardless of what conditions the caller specifies, all successfully
- // installed traps also implicitly observe IPCZ_TRAP_REMOVED.
- //
- // If successful, ipcz guarantees that `handler` will be invoked -- with the
- // the `context` field of the invocation's IpczTrapEvent reflecting the value
- // of `context` given here -- once any of the specified conditions have been
- // met.
- //
- // Immediately before invoking its handler, the trap is removed from the
- // portal and must be reinstalled in order to observe further state changes.
- //
- // When a portal is closed, any traps still installed on it are notified by
- // invoking their handler with IPCZ_TRAP_REMOVED in the event's
- // `condition_flags`. This effectively guarantees that all installed traps
- // eventually see a handler invocation.
- //
- // Note that `handler` may be invoked from any thread that can modify the
- // state of the observed portal. This is limited to threads which make direct
- // ipcz calls on the portal, and any threads on which the portal's node may
- // receive notifications from a driver transport.
- //
- // If any of the specified conditions are already met, the trap is not
- // installed and this call returns IPCZ_RESULT_FAILED_PRECONDITION. See below
- // for details.
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the trap was installed successfully. In this case
- // `flags` and `status` arguments are ignored.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `conditions` is
- // null or invalid, `handler` is null, or `status` is non-null but its
- // `size` field specifies an invalid value.
- //
- // IPCZ_RESULT_FAILED_PRECONDITION if the conditions specified are already
- // met on the portal. If `satisfied_condition_flags` is non-null, then
- // its pointee value will be updated to reflect the flags in
- // `conditions` which were already satisfied by the portal's state. If
- // `status` is non-null, a copy of the portal's last known status will
- // also be stored there.
- IpczResult(IPCZ_API* Trap)(
- IpczHandle portal, // in
- const struct IpczTrapConditions* conditions, // in
- IpczTrapEventHandler handler, // in
- uintptr_t context, // in
- uint32_t flags, // in
- const void* options, // in
- IpczTrapConditionFlags* satisfied_condition_flags, // out
- struct IpczPortalStatus* status); // out
- // Boxes an object managed by a node's driver and returns a new IpczHandle to
- // reference the box. If the driver is able to serialize the boxed object, the
- // box can be placed into a portal for transmission to the other side.
- //
- // Boxes can be sent through portals along with other IpczHandles, effectively
- // allowing drivers to introduce new types of transferrable objects via boxes.
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the driver handle was boxed and a new IpczHandle is
- // returned in `handle`.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `driver_handle` was invalid.
- IpczResult(IPCZ_API* Box)(IpczHandle node, // in
- IpczDriverHandle driver_handle, // in
- uint32_t flags, // in
- const void* options, // in
- IpczHandle* handle); // out
- // Unboxes a driver object from an IpczHandle previously produced by Box().
- //
- // `flags` is ignored and must be 0.
- //
- // `options` is ignored and must be null.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if the driver object was successfully unboxed. A driver
- // handle to the object is placed in `*driver_handle`.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `handle` is invalid or does not
- // reference a box.
- IpczResult(IPCZ_API* Unbox)(IpczHandle handle, // in
- IpczUnboxFlags flags, // in
- const void* options, // in
- IpczDriverHandle* driver_handle); // out
- };
- // A function which populates `api` with a table of ipcz API functions. The
- // `size` field must be set by the caller to the size of the structure before
- // issuing this call.
- //
- // In practice ipcz defines IpczGetAPI() as an implementation of this function
- // type. How applications acquire a reference to that function depends on how
- // the application builds and links against ipcz.
- //
- // Upon return, `api->size` indicates the size of the function table actually
- // populated and therefore which version of the ipcz implementation is in use.
- // Note that this size will never exceed the input value of `api->size`: if the
- // caller is built against an older version than what is available, the
- // available implementation will only populate the functions appropriate for
- // that older version. Conversely if the caller is built against a newer version
- // than what is available, `api->size` on output may be smaller than its value
- // was on input.
- //
- // Returns:
- //
- // IPCZ_RESULT_OK if `api` was successfully populated. In this case
- // `api->size` effectively indicates the API version provided, and the
- // appropriate function pointers within `api` are filled in.
- //
- // IPCZ_RESULT_INVALID_ARGUMENT if `api` is null or the caller's provided
- // `api->size` is less than the size of the function table required to
- // host API version 0.
- typedef IpczResult(IPCZ_API* IpczGetAPIFn)(struct IpczAPI* api);
- #if defined(__cplusplus)
- } // extern "C"
- #endif
- #endif // IPCZ_INCLUDE_IPCZ_IPCZ_H_
|