ipcz.h 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef IPCZ_INCLUDE_IPCZ_IPCZ_H_
  5. #define IPCZ_INCLUDE_IPCZ_IPCZ_H_
  6. // ipcz is a cross-platform C library for interprocess communication (IPC) which
  7. // supports efficient routing and data transfer over a large number of
  8. // dynamically relocatable messaging endpoints.
  9. //
  10. // ipcz operates in terms of a small handful of abstractions encapsulated in
  11. // this header: nodes, portals, parcels, drivers, boxes, and traps.
  12. //
  13. // NOTE: This header is intended to compile under C++11 or newer, and C99 or
  14. // newer. The ABI defined here can be considered stable.
  15. //
  16. // Glossary
  17. // --------
  18. // *Nodes* are used by ipcz to model isolated units of an application. A typical
  19. // application will create one ipcz node within each OS process it controls.
  20. //
  21. // *Portals* are messaging endpoints which belong to a specific node. Portals
  22. // are created in entangled pairs: whatever goes into one portal comes out the
  23. // other (its "peer"). Pairs may be created local to a single node, or they may
  24. // be created to span two nodes. Portals may also be transferred freely through
  25. // other portals.
  26. //
  27. // *Parcels* are the unit of communication between portals. Parcels can contain
  28. // arbitrary application data as well as ipcz handles. Handles within a parcel
  29. // are used to transfer objects (namely other portals, or driver-defined
  30. // objects) from one portal to another, potentially on a different node.
  31. //
  32. // *Traps* provide a flexible mechanism to observe interesting portal state
  33. // changes such as new parcels arriving or a portal's peer being closed.
  34. //
  35. // *Drivers* are provided by applications to implement platform-specific IPC
  36. // details. They may also define new types of objects to be transmitted in
  37. // parcels via boxes.
  38. //
  39. // *Boxes* are opaque objects used to wrap driver-defined objects for seamless
  40. // transmission across portals. Drivers define how to serialize and deserialize
  41. // such objects, and applications use the Box() and Unbox() APIs to go between
  42. // concrete driver objects and transferrable handles.
  43. //
  44. // Overview
  45. // --------
  46. // To use ipcz effectively, an application must create multiple nodes to be
  47. // interconnected. One node must be designated as the "broker" by the
  48. // application (see CreateNode() flags). The broker is used by ipcz to
  49. // coordinate certain types of internal transactions which demand a heightened
  50. // level of trust and capability, so a broker node should always live in a more
  51. // trustworthy process. For example in Chrome, the browser process is
  52. // designated as the broker.
  53. //
  54. // In order for a node to communicate with other nodes in the system, the
  55. // application must explicitly connect it to ONE other node using the
  56. // ConnectNode() API. Once this is done, ipcz can automatically connect the node
  57. // to additional other nodes as needed for efficient portal operation.
  58. //
  59. // In the example below, assume node A is designated as the broker. Nodes A and
  60. // B have been connected directly by ConnectNode() calls in the application.
  61. // Nodes A and C have been similarly connected:
  62. //
  63. // ┌───────┐
  64. // ConnectNode() │ │ ConnectNode()
  65. // ┌──────────>O A O<───────────┐
  66. // │ │ │ │
  67. // │ └───────┘ │
  68. // │ │
  69. // v ConnectNode() v ConnectNode()
  70. // ┌───O───┐ ┌───O───┐
  71. // │ │ │ │
  72. // │ B │ │ C │
  73. // │ │ │ │
  74. // └───────┘ └───────┘
  75. //
  76. // ConnectNode() establishes initial portal pairs to link the two nodes
  77. // together, illustrated above as "O"s. Once ConnectNode() returns, the
  78. // application may immediately begin transmitting parcels through these portals.
  79. //
  80. // Now suppose node B creates a new local pair of portals (using OpenPortals())
  81. // and sends one of those new portals in a parcel through its
  82. // already-established portal to node A. The sent portal is effectively
  83. // transferred to node A, and because its entangled peer still lives on node B
  84. // there are now TWO portal pairs between nodes A and B:
  85. //
  86. // ┌───────┐
  87. // │ │
  88. // ┌──────────>O A O<───────────┐
  89. // │ ┌────────>O │ │
  90. // │ │ └───────┘ │
  91. // │ │ │
  92. // v v v
  93. // ┌───O─O─┐ ┌───O───┐
  94. // │ │ │ │
  95. // │ B │ │ C │
  96. // │ │ │ │
  97. // └───────┘ └───────┘
  98. //
  99. // Finally, suppose now the application takes this new portal on node A and
  100. // sends it further along, through node A's already-established portal to node
  101. // C. Because the transferred portal's peer still lives on node B, there is now
  102. // a portal pair spanning nodes B and C:
  103. //
  104. // ┌───────┐
  105. // │ │
  106. // ┌──────────>O A O<───────────┐
  107. // │ │ │ │
  108. // │ └───────┘ │
  109. // │ │
  110. // v v
  111. // ┌───O───┐ ┌───O───┐
  112. // │ │ │ │
  113. // │ B O────────────────────────O C │
  114. // │ │ │ │
  115. // └───────┘ └───────┘
  116. //
  117. // These two nodes were never explicitly connected by the application, but ipcz
  118. // ensures that the portals will operate as expected. Behind the scenes, ipcz
  119. // achieves this by establishing a direct, secure, and efficient communication
  120. // channel between nodes B and C.
  121. #include <stddef.h>
  122. #include <stdint.h>
  123. #define IPCZ_NO_FLAGS ((uint32_t)0)
  124. // Helper to clarify flag definitions.
  125. #define IPCZ_FLAG_BIT(bit) ((uint32_t)(1u << bit))
  126. // Opaque handle to an ipcz object.
  127. typedef uintptr_t IpczHandle;
  128. // An IpczHandle value which is always invalid. Note that arbitrary non-zero
  129. // values are not necessarily valid either, but zero is never valid.
  130. #define IPCZ_INVALID_HANDLE ((IpczHandle)0)
  131. // Generic result code for all ipcz operations. See IPCZ_RESULT_* values below.
  132. typedef int IpczResult;
  133. // Specific meaning of each value depends on context, but IPCZ_RESULT_OK always
  134. // indicates success. These values are derived from common status code
  135. // definitions across Google software.
  136. #define IPCZ_RESULT_OK ((IpczResult)0)
  137. #define IPCZ_RESULT_CANCELLED ((IpczResult)1)
  138. #define IPCZ_RESULT_UNKNOWN ((IpczResult)2)
  139. #define IPCZ_RESULT_INVALID_ARGUMENT ((IpczResult)3)
  140. #define IPCZ_RESULT_DEADLINE_EXCEEDED ((IpczResult)4)
  141. #define IPCZ_RESULT_NOT_FOUND ((IpczResult)5)
  142. #define IPCZ_RESULT_ALREADY_EXISTS ((IpczResult)6)
  143. #define IPCZ_RESULT_PERMISSION_DENIED ((IpczResult)7)
  144. #define IPCZ_RESULT_RESOURCE_EXHAUSTED ((IpczResult)8)
  145. #define IPCZ_RESULT_FAILED_PRECONDITION ((IpczResult)9)
  146. #define IPCZ_RESULT_ABORTED ((IpczResult)10)
  147. #define IPCZ_RESULT_OUT_OF_RANGE ((IpczResult)11)
  148. #define IPCZ_RESULT_UNIMPLEMENTED ((IpczResult)12)
  149. #define IPCZ_RESULT_INTERNAL ((IpczResult)13)
  150. #define IPCZ_RESULT_UNAVAILABLE ((IpczResult)14)
  151. #define IPCZ_RESULT_DATA_LOSS ((IpczResult)15)
  152. // Helper to specify explicit struct alignment across C and C++ compilers.
  153. #if defined(__cplusplus)
  154. #define IPCZ_ALIGN(alignment) alignas(alignment)
  155. #elif defined(__GNUC__)
  156. #define IPCZ_ALIGN(alignment) __attribute__((aligned(alignment)))
  157. #elif defined(_MSC_VER)
  158. #define IPCZ_ALIGN(alignment) __declspec(align(alignment))
  159. #else
  160. #error "IPCZ_ALIGN() is not defined for your compiler."
  161. #endif
  162. // Helper to generate the smallest constant value which is aligned with
  163. // `alignment` and at least as large as `value`.
  164. #define IPCZ_ALIGNED(value, alignment) \
  165. ((((value) + ((alignment)-1)) / (alignment)) * (alignment))
  166. // Helper used to explicitly specify calling convention or other
  167. // compiler-specific annotations for each API function.
  168. #if defined(IPCZ_API_OVERRIDE)
  169. #define IPCZ_API IPCZ_API_OVERRIDE
  170. #elif defined(_WIN32)
  171. #define IPCZ_API __cdecl
  172. #else
  173. #define IPCZ_API
  174. #endif
  175. // An opaque handle value created by an IpczDriver implementation. ipcz uses
  176. // such handles to provide relevant context when calling back into the driver.
  177. typedef uintptr_t IpczDriverHandle;
  178. #define IPCZ_INVALID_DRIVER_HANDLE ((IpczDriverHandle)0)
  179. // Flags given to the ipcz activity handler by a driver transport to notify ipcz
  180. // about incoming data or state changes.
  181. typedef uint32_t IpczTransportActivityFlags;
  182. // If set, the driver encountered an unrecoverable error using the transport and
  183. // ipcz should discard it. Note that the driver is free to issue such
  184. // notifications many times as long as it remans active, but ipcz will generally
  185. // request deactivation ASAP once an error is signaled.
  186. #define IPCZ_TRANSPORT_ACTIVITY_ERROR IPCZ_FLAG_BIT(0)
  187. // When ipcz wants to deactivate a transport, it invokes the driver's
  188. // DeactivateTransport() function. Once the driver has finished any clean up and
  189. // can ensure that the transport's activity handler will no longer be invoked,
  190. // it must then invoke the activity handler one final time with this flag set.
  191. // This finalizes deactivation and allows ipcz to free any associated resources.
  192. #define IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED IPCZ_FLAG_BIT(1)
  193. #if defined(__cplusplus)
  194. extern "C" {
  195. #endif
  196. // Notifies ipcz of activity on a transport. `transport` must be a handle to a
  197. // transport which is currently activated. The `transport` handle is acquired
  198. // exclusively by the driver transport via an ipcz call to the driver's
  199. // ActivateTransport(), which also provides the handle to the driver.
  200. //
  201. // The driver must use this function to feed incoming data and driver handles
  202. // from the transport to ipcz, or to inform ipcz of any error conditions
  203. // resulting in unexpected and irrecoverable dysfunction of the transport.
  204. //
  205. // If the driver encounters an unrecoverable error while performing I/O on the
  206. // transport, it should invoke this with the IPCZ_TRANSPORT_ACTIVITY_ERROR flag
  207. // to instigate deactivation of the transport by ipcz via a subsequent
  208. // DeactivateTransport() call.
  209. //
  210. // `options` is currently unused and must be null.
  211. //
  212. // NOTE: It is the driver's responsibility to ensure that calls to this function
  213. // for the same value of `transport` are mututally exclusive. Overlapping calls
  214. // are unsafe and will result in undefined behavior.
  215. typedef IpczResult(IPCZ_API* IpczTransportActivityHandler)(
  216. IpczHandle transport, // in
  217. const void* data, // in
  218. size_t num_bytes, // in
  219. const IpczDriverHandle* driver_handles, // in
  220. size_t num_driver_handles, // in
  221. IpczTransportActivityFlags flags, // in
  222. const void* options); // in
  223. // Structure to be filled in by a driver's GetSharedMemoryInfo().
  224. struct IPCZ_ALIGN(8) IpczSharedMemoryInfo {
  225. // The exact size of this structure in bytes. Set by ipcz before passing the
  226. // structure to the driver.
  227. size_t size;
  228. // The size of the shared memory region in bytes.
  229. size_t region_num_bytes;
  230. };
  231. // IpczDriver is a function table to be populated by the application and
  232. // provided to ipcz when creating a new node. The driver implements concrete
  233. // I/O operations to facilitate communication between nodes, giving embedding
  234. // systems full control over choice of OS-specific transport mechanisms and I/O
  235. // scheduling decisions.
  236. //
  237. // The driver API is meant to be used by both the application embedding ipcz,
  238. // particularly for creating transports to make initial contact between nodes,
  239. // as well as by ipcz itself to delegate creation and management of new
  240. // transports which ipcz brokers between nodes.
  241. struct IPCZ_ALIGN(8) IpczDriver {
  242. // The exact size of this structure in bytes. Must be set accurately by the
  243. // application before passing this structure to any ipcz API functions.
  244. size_t size;
  245. // Called by ipcz to request that the driver release the object identified by
  246. // `handle`.
  247. IpczResult(IPCZ_API* Close)(IpczDriverHandle handle, // in
  248. uint32_t flags, // in
  249. const void* options); // in
  250. // Serializes a driver object identified by `handle` into a collection of
  251. // bytes and readily transmissible driver objects, for eventual transmission
  252. // over `transport`. At a minimum this must support serialization of transport
  253. // and memory objects allocated by ipcz through the driver. Any other driver
  254. // objects intended for applications to box and transmit through portals must
  255. // also be serializable here.
  256. //
  257. // If the specified object is invalid or unserializable, the driver must
  258. // ignore all other arguments (including `transport`) and return
  259. // IPCZ_RESULT_INVALID_ARGUMENT.
  260. //
  261. // If the object can be serialized but success may depend on the value of
  262. // `transport`, and `transport` is IPCZ_INVALID_DRIVER_HANDLE, the driver must
  263. // return IPCZ_RESULT_ABORTED. ipcz may invoke Serialize() in this way to
  264. // query whether a specific object can be serialized at all, even when it
  265. // doesn't have a specific transport in mind.
  266. //
  267. // If the object can be serialized or transmitted as-is and `transport` is
  268. // valid, but the serialized outputs would not be transmissible over
  269. // `transport` specifically, the driver must ignore all other arguments and
  270. // return IPCZ_RESULT_PERMISSION_DENIED. This implies that neither end of
  271. // `transport` is sufficiently privileged or otherwise able to transfer the
  272. // object directly, and in this case ipcz may instead attempt to relay the
  273. // object through a more capable broker node.
  274. //
  275. // For all other outcomes, the object identified by `handle` is considered to
  276. // be serializable and ultimately transmissible.
  277. //
  278. // `num_bytes` and `num_handles` on input point to the capacities of the
  279. // respective output buffers provided by ipcz. If either capacity pointer is
  280. // null, a capacity of zero is implied; and if either input capacity is zero,
  281. // the corresponding input buffer may be null.
  282. //
  283. // Except in the failure modes described above, the driver must update any
  284. // non-null capacity input to reflect the exact capacity required to serialize
  285. // the object. For example if `num_bytes` is non-null and the object
  286. // serializes to 8 bytes of data, `*num_bytes` must be set to 8 upon return.
  287. //
  288. // If the required data or handle capacity is larger than the respective input
  289. // capacity, the driver must return IPCZ_RESULT_RESUORCE_EXHAUSTED without
  290. // modifying the contents of either `data` or `handles` buffers.
  291. //
  292. // Finally, if the input capacities were both sufficient, the driver must fill
  293. // `data` and `handles` with a serialized representation of the object and
  294. // return IPCZ_RESULT_OK. In this case ipcz relinquishes `handle` and will no
  295. // longer refer to it unless the driver outputs it back in `handles`, implying
  296. // that it was already transmissible as-is.
  297. IpczResult(IPCZ_API* Serialize)(IpczDriverHandle handle, // in
  298. IpczDriverHandle transport, // in
  299. uint32_t flags, // in
  300. const void* options, // in
  301. void* data, // out
  302. size_t* num_bytes, // in/out
  303. IpczDriverHandle* handles, // out
  304. size_t* num_handles); // in/out
  305. // Deserializes a driver object from a collection of bytes and transmissible
  306. // driver objects which which was originally produced by Serialize() and
  307. // received on the calling node via `transport`.
  308. //
  309. // Any return value other than IPCZ_RESULT_OK indicates an error and implies
  310. // that `handle` is unmodified. Otherwise `handle` must contain a valid driver
  311. // handle to the deserialized object.
  312. IpczResult(IPCZ_API* Deserialize)(
  313. const void* data, // in
  314. size_t num_bytes, // in
  315. const IpczDriverHandle* driver_handles, // in
  316. size_t num_driver_handles, // in
  317. IpczDriverHandle transport, // in
  318. uint32_t flags, // in
  319. const void* options, // in
  320. IpczDriverHandle* handle); // out
  321. // Creates a new pair of entangled bidirectional transports, returning them in
  322. // `new_transport0` and `new_transport1`.
  323. //
  324. // The input `transport0` and `transport1` are provided for context which may
  325. // be important to the driver: the output transport in `new_transport0` will
  326. // be sent over `transport0`, while the output transport in `new_transport1`
  327. // will be sent over `transport1`. That is, the new transport is being created
  328. // to establish a direct link between the remote node on `transport0` and the
  329. // remote node on `transport1`.
  330. //
  331. // Any return value other than IPCZ_RESULT_OK indicates an error and implies
  332. // that `new_transport0` and `new_transport1` are unmodified.
  333. IpczResult(IPCZ_API* CreateTransports)(
  334. IpczDriverHandle transport0, // in
  335. IpczDriverHandle transport1, // in
  336. uint32_t flags, // in
  337. const void* options, // in
  338. IpczDriverHandle* new_transport0, // out
  339. IpczDriverHandle* new_transport1); // out
  340. // Called by ipcz to activate a transport. `driver_transport` is the
  341. // driver-side handle assigned to the transport by the driver, either as given
  342. // to ipcz via ConnectNode(), or as returned by the driver from an ipcz call
  343. // out to CreateTransports().
  344. //
  345. // `transport` is a handle the driver can use when calling `activity_handler`
  346. // to update ipcz regarding any incoming data or state changes from the
  347. // transport.
  348. //
  349. // Before this returns, the driver should establish any I/O monitoring or
  350. // scheduling state necessary to support operation of the endpoint, and once
  351. // it returns ipcz may immediately begin making Transmit() calls on
  352. // `driver_transport`.
  353. //
  354. // Any return value other than IPCZ_RESULT_OK indicates an error, and the
  355. // endpoint will be dropped by ipcz. Otherwise the endpoint may be used
  356. // immediately to accept or submit data, and it should continue to operate
  357. // until ipcz calls Close() on `driver_transport`.
  358. //
  359. // Note that `activity_handler` invocations MUST be mutually exclusive,
  360. // because transmissions from ipcz are expected to arrive and be processed
  361. // strictly in-order.
  362. //
  363. // The driver may elicit forced destruction of itself by calling
  364. // `activity_handler` with the flag IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED.
  365. IpczResult(IPCZ_API* ActivateTransport)(
  366. IpczDriverHandle driver_transport, // in
  367. IpczHandle transport, // in
  368. IpczTransportActivityHandler activity_handler, // in
  369. uint32_t flags, // in
  370. const void* options); // in
  371. // Called by ipcz to deactivate a transport. The driver does not need to
  372. // complete deactivation synchronously, but it must begin to deactivate the
  373. // transport and must invoke the transport's activity handler one final time
  374. // with IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED once finished. Beyond that point,
  375. // the activity handler must no longer be invoked for that transport.
  376. //
  377. // Note that even after deactivatoin, ipcz may continue to call into the
  378. // transport until it's closed with an explicit call to the driver's Close()
  379. // by ipcz.
  380. IpczResult(IPCZ_API* DeactivateTransport)(
  381. IpczDriverHandle driver_transport, // in
  382. uint32_t flags, // in
  383. const void* options); // in
  384. // Called by ipcz to delegate transmission of data and driver handles over the
  385. // identified transport endpoint. If the driver cannot fulfill the request,
  386. // it must return a result other than IPCZ_RESULT_OK, and this will cause the
  387. // transport's connection to be severed.
  388. //
  389. // Note that any driver handles in `driver_handles` were obtained by ipcz from
  390. // the driver itself, by some prior call to the driver's own Serialize()
  391. // function. These handles are therefore expected to be directly transmissible
  392. // by the driver alongside any data in `data`.
  393. //
  394. // The net result of this transmission should be an activity handler
  395. // invocation on the corresponding remote transport by the driver on its node.
  396. // It is the driver's responsibility to get any data and handles to the other
  397. // transport, and to ensure that all transmissions from transport end up
  398. // invoking the activity handler on the peer transport in the same order they
  399. // were transmitted.
  400. //
  401. // If ipcz only wants to wake the peer node rather than transmit data or
  402. // handles, `num_bytes` and `num_driver_handles` may both be zero.
  403. IpczResult(IPCZ_API* Transmit)(IpczDriverHandle driver_transport, // in
  404. const void* data, // in
  405. size_t num_bytes, // in
  406. const IpczDriverHandle* driver_handles, // in
  407. size_t num_driver_handles, // in
  408. uint32_t flags, // in
  409. const void* options); // in
  410. // Allocates a shared memory region and returns a driver handle in
  411. // `driver_memory` which can be used to reference it in other calls to the
  412. // driver.
  413. IpczResult(IPCZ_API* AllocateSharedMemory)(
  414. size_t num_bytes, // in
  415. uint32_t flags, // in
  416. const void* options, // in
  417. IpczDriverHandle* driver_memory); // out
  418. // Returns information about the shared memory region identified by
  419. // `driver_memory`.
  420. IpczResult(IPCZ_API* GetSharedMemoryInfo)(
  421. IpczDriverHandle driver_memory, // in
  422. uint32_t flags, // in
  423. const void* options, // in
  424. struct IpczSharedMemoryInfo* info); // out
  425. // Duplicates a shared memory region handle into a new distinct handle
  426. // referencing the same underlying region.
  427. IpczResult(IPCZ_API* DuplicateSharedMemory)(
  428. IpczDriverHandle driver_memory, // in
  429. uint32_t flags, // in
  430. const void* options, // in
  431. IpczDriverHandle* new_driver_memory); // out
  432. // Maps a shared memory region identified by `driver_memory` and returns its
  433. // mapped address in `address` on success and a driver handle in
  434. // `driver_mapping` which can be passed to the driver's Close() to unmap the
  435. // region later.
  436. //
  437. // Note that the lifetime of `driver_mapping` should be independent from that
  438. // of `driver_memory`. That is, if `driver_memory` is closed immediately after
  439. // this call succeeds, the returned mapping must still remain valid until the
  440. // mapping itself is closed.
  441. IpczResult(IPCZ_API* MapSharedMemory)(
  442. IpczDriverHandle driver_memory, // in
  443. uint32_t flags, // in
  444. const void* options, // in
  445. void** address, // out
  446. IpczDriverHandle* driver_mapping); // out
  447. // Generates `num_bytes` bytes of random data to fill `buffer`.
  448. IpczResult(IPCZ_API* GenerateRandomBytes)(size_t num_bytes, // in
  449. uint32_t flags, // in
  450. const void* options, // in
  451. void* buffer); // out
  452. };
  453. #if defined(__cplusplus)
  454. } // extern "C"
  455. #endif
  456. // See CreateNode() and the IPCZ_CREATE_NODE_* flag descriptions below.
  457. typedef uint32_t IpczCreateNodeFlags;
  458. // Indicates that the created node will serve as the broker in its cluster.
  459. //
  460. // Brokers are expected to live in relatively trusted processes -- not
  461. // necessarily elevated in privilege but also generally not restricted by
  462. // sandbox constraints and not prone to processing risky, untrusted data -- as
  463. // they're responsible for helping other nodes establish direct lines of
  464. // communication as well as in some cases relaying data and driver handles
  465. // between lesser-privileged nodes.
  466. //
  467. // Broker nodes do not expose any additional ipcz APIs or require much other
  468. // special care on the part of the application**, but every cluster of connected
  469. // nodes must have a node designated as the broker. Typically this is the first
  470. // node created by an application's main process or a system-wide service
  471. // coordinator, and all other nodes are created in processes spawned by that one
  472. // or in processes which otherwise trust it.
  473. //
  474. // ** See notes on Close() regarding destruction of broker nodes.
  475. #define IPCZ_CREATE_NODE_AS_BROKER IPCZ_FLAG_BIT(0)
  476. // See ConnectNode() and the IPCZ_CONNECT_NODE_* flag descriptions below.
  477. typedef uint32_t IpczConnectNodeFlags;
  478. // Indicates that the remote node for this connection is expected to be a broker
  479. // node, and it will be treated as such. Do not use this flag when connecting to
  480. // any untrusted process.
  481. #define IPCZ_CONNECT_NODE_TO_BROKER IPCZ_FLAG_BIT(0)
  482. // Indicates that the remote node for this connection is expected not to be a
  483. // broker, but to already have a link to a broker; and that the calling node
  484. // wishes to inherit the remote node's broker as well. This flag must only be
  485. // used when connecting to a node the caller trusts. The calling node must not
  486. // already have an established broker from a previous ConnectNode() call. The
  487. // remote node must specify IPCZ_CONNECT_NODE_SHARE_BROKER as well.
  488. #define IPCZ_CONNECT_NODE_INHERIT_BROKER IPCZ_FLAG_BIT(1)
  489. // Indicates that the calling node already has a broker, and that this broker
  490. // will be inherited by the remote node. The remote node must also specify
  491. // IPCZ_CONNECT_NODE_INHERIT_BROKER in its corresponding ConnectNode() call.
  492. #define IPCZ_CONNECT_NODE_SHARE_BROKER IPCZ_FLAG_BIT(2)
  493. // ipcz may periodically allocate shared memory regions to facilitate
  494. // communication between two nodes. In many runtime environments, even within
  495. // a security sandbox, the driver can do do this safely and directly by
  496. // interfacing with the OS. In some environments however, direct allocation is
  497. // not possible. In such cases a node must delegate this responsibility to some
  498. // other trusted node in the system, typically the broker node.
  499. //
  500. // Specifying this flag ensures that all shared memory allocation elicited by
  501. // the connecting node will be delegated to the connectee.
  502. #define IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE IPCZ_FLAG_BIT(3)
  503. // Optional limits provided by IpczPutOptions for Put() or IpczBeginPutOptions
  504. // for BeginPut().
  505. struct IPCZ_ALIGN(8) IpczPutLimits {
  506. // The exact size of this structure in bytes. Must be set accurately before
  507. // passing the structure to any API functions.
  508. size_t size;
  509. // Specifies the maximum number of unread parcels to allow in a portal's
  510. // queue. If a Put() or BeginPut() call specifying this limit would cause the
  511. // receiver's number of number of queued unread parcels to exceed this value,
  512. // the call will fail with IPCZ_RESULT_RESOURCE_EXHAUSTED.
  513. size_t max_queued_parcels;
  514. // Specifies the maximum number of data bytes to allow in a portal's queue.
  515. // If a Put() or BeginPut() call specifying this limit would cause the number
  516. // of data bytes across all queued unread parcels to exceed this value, the
  517. // call will fail with IPCZ_RESULT_RESOURCE_EXHAUSTED.
  518. size_t max_queued_bytes;
  519. };
  520. // Options given to Put() to modify its default behavior.
  521. struct IPCZ_ALIGN(8) IpczPutOptions {
  522. // The exact size of this structure in bytes. Must be set accurately before
  523. // passing the structure to Put().
  524. size_t size;
  525. // Optional limits to apply when determining if the Put() should be completed.
  526. const struct IpczPutLimits* limits;
  527. };
  528. // See BeginPut() and the IPCZ_BEGIN_PUT_* flags described below.
  529. typedef uint32_t IpczBeginPutFlags;
  530. // Indicates that the caller is willing to produce less data than originally
  531. // requested by their `*num_bytes` argument to BeginPut(). If the implementation
  532. // would prefer a smaller chunk of data or if the requested size would exceed
  533. // limits specified in the call's corresponding IpczPutLimits, passing this flag
  534. // may allow the call to succeed while returning a smaller acceptable value in
  535. // `*num_bytes`, rather than simply failing the call with
  536. // IPCZ_RESULT_RESOURCE_EXHAUSTED.
  537. #define IPCZ_BEGIN_PUT_ALLOW_PARTIAL IPCZ_FLAG_BIT(0)
  538. // Options given to BeginPut() to modify its default behavior.
  539. struct IPCZ_ALIGN(8) IpczBeginPutOptions {
  540. // The exact size of this structure in bytes. Must be set accurately before
  541. // passing the structure to BeginPut().
  542. size_t size;
  543. // Optional limits to apply when determining if the BeginPut() should be
  544. // completed.
  545. const struct IpczPutLimits* limits;
  546. };
  547. // See EndPut() and the IPCZ_END_PUT_* flags described below.
  548. typedef uint32_t IpczEndPutFlags;
  549. // If this flag is given to EndPut(), any in-progress two-phase put operation is
  550. // aborted without committing a parcel to the portal.
  551. #define IPCZ_END_PUT_ABORT IPCZ_FLAG_BIT(0)
  552. // See Get() and the IPCZ_GET_* flag descriptions below.
  553. typedef uint32_t IpczGetFlags;
  554. // When given to Get(), this flag indicates that the caller is willing to accept
  555. // a partial retrieval of the next available parcel. This means that in
  556. // situations where Get() would normally return IPCZ_RESULT_RESOURCE_EXHAUSTED,
  557. // it will instead return IPCZ_RESULT_OK with as much data and handles as the
  558. // caller indicated they could accept.
  559. #define IPCZ_GET_PARTIAL IPCZ_FLAG_BIT(0)
  560. // See EndGet() and the IPCZ_END_GET_* flag descriptions below.
  561. typedef uint32_t IpczEndGetFlags;
  562. // If this flag is given to EndGet(), any in-progress two-phase get operation is
  563. // aborted without consuming any data from the portal.
  564. #define IPCZ_END_GET_ABORT IPCZ_FLAG_BIT(0)
  565. // See Unbox() and the IPCZ_UNBOX_* flags described below.
  566. typedef uint32_t IpczUnboxFlags;
  567. // If set, the box is not consumed and the driver handle returned is not removed
  568. // from the box.
  569. #define IPCZ_UNBOX_PEEK IPCZ_FLAG_BIT(0)
  570. // Flags given by the `flags` field in IpczPortalStatus.
  571. typedef uint32_t IpczPortalStatusFlags;
  572. // Indicates that the opposite portal is closed. Subsequent put operations on
  573. // this portal will always fail with IPCZ_RESULT_NOT_FOUND. If there are not
  574. // currently any unretrieved parcels in the portal either, subsequent get
  575. // operations will also fail with the same error.
  576. #define IPCZ_PORTAL_STATUS_PEER_CLOSED IPCZ_FLAG_BIT(0)
  577. // Indicates that the opposite portal is closed AND no more parcels can be
  578. // expected to arrive from it. If this bit is set on a portal's status, the
  579. // portal is essentially useless. Such portals no longer support Put() or
  580. // Get() operations, and those operations will subsequently always return
  581. // IPCZ_RESULT_NOT_FOUND.
  582. #define IPCZ_PORTAL_STATUS_DEAD IPCZ_FLAG_BIT(1)
  583. // Information returned by QueryPortalStatus() or provided to
  584. // IpczTrapEventHandlers when a trap's conditions are met on a portal.
  585. struct IPCZ_ALIGN(8) IpczPortalStatus {
  586. // The exact size of this structure in bytes. Must be set accurately before
  587. // passing the structure to any functions.
  588. size_t size;
  589. // Flags. See the IPCZ_PORTAL_STATUS_* flags described above for the possible
  590. // flags combined in this value.
  591. IpczPortalStatusFlags flags;
  592. // The number of unretrieved parcels queued on this portal.
  593. size_t num_local_parcels;
  594. // The number of unretrieved bytes (across all unretrieved parcels) queued on
  595. // this portal.
  596. size_t num_local_bytes;
  597. // The number of unretrieved parcels queued on the opposite portal.
  598. size_t num_remote_parcels;
  599. // The number of unretrieved bytes (across all unretrieved parcels) queued on
  600. // the opposite portal.
  601. size_t num_remote_bytes;
  602. };
  603. // Flags given to IpczTrapConditions to indicate which types of conditions a
  604. // trap should observe.
  605. //
  606. // Note that each type of condition may be considered edge-triggered or
  607. // level-triggered. An edge-triggered condition is one which is only
  608. // observable momentarily in response to a state change, while a level-triggered
  609. // condition is continuously observable as long as some constraint about a
  610. // portal's state is met.
  611. //
  612. // Level-triggered conditions can cause a Trap() attempt to fail if they're
  613. // already satisfied when attempting to install a trap to monitor them.
  614. typedef uint32_t IpczTrapConditionFlags;
  615. // Triggers a trap event when the trap's portal is itself closed. This condition
  616. // is always observed even if not explicitly set in the IpczTrapConditions given
  617. // to the Trap() call. If a portal is closed while a trap is installed on it,
  618. // an event will fire for the trap with this condition flag set. This condition
  619. // is effectively edge-triggered, because as soon as it becomes true, any
  620. // observing trap as well as its observed subject cease to exist.
  621. #define IPCZ_TRAP_REMOVED IPCZ_FLAG_BIT(0)
  622. // Triggers a trap event whenever the opposite portal is closed. Typically
  623. // applications are interested in the more specific IPCZ_TRAP_DEAD.
  624. // Level-triggered.
  625. #define IPCZ_TRAP_PEER_CLOSED IPCZ_FLAG_BIT(1)
  626. // Triggers a trap event whenever there are no more parcels available to
  627. // retrieve from this portal AND the opposite portal is closed. This means the
  628. // portal will never again have parcels to retrieve and is effectively useless.
  629. // Level-triggered.
  630. #define IPCZ_TRAP_DEAD IPCZ_FLAG_BIT(2)
  631. // Triggers a trap event whenever the number of parcels queued for retrieval by
  632. // this portal exceeds the threshold given by `min_local_parcels` in
  633. // IpczTrapConditions. Level-triggered.
  634. #define IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS IPCZ_FLAG_BIT(3)
  635. // Triggers a trap event whenever the number of bytes queued for retrieval by
  636. // this portal exceeds the threshold given by `min_local_bytes` in
  637. // IpczTrapConditions. Level-triggered.
  638. #define IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES IPCZ_FLAG_BIT(4)
  639. // Triggers a trap event whenever the number of parcels queued for retrieval on
  640. // the opposite portal drops below the threshold given by `max_remote_parcels`
  641. // IpczTrapConditions. Level-triggered.
  642. #define IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS IPCZ_FLAG_BIT(5)
  643. // Triggers a trap event whenever the number of bytes queued for retrieval on
  644. // the opposite portal drops below the threshold given by `max_remote_bytes` in
  645. // IpczTrapConditions. Level-triggered.
  646. #define IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES IPCZ_FLAG_BIT(6)
  647. // Triggers a trap event whenever the number of locally available parcels
  648. // increases by any amount. Edge-triggered.
  649. #define IPCZ_TRAP_NEW_LOCAL_PARCEL IPCZ_FLAG_BIT(7)
  650. // Triggers a trap event whenever the number of queued remote parcels decreases
  651. // by any amount. Edge-triggered.
  652. #define IPCZ_TRAP_CONSUMED_REMOTE_PARCEL IPCZ_FLAG_BIT(8)
  653. // A structure describing portal conditions necessary to trigger a trap and
  654. // invoke its event handler.
  655. struct IPCZ_ALIGN(8) IpczTrapConditions {
  656. // The exact size of this structure in bytes. Must be set accurately before
  657. // passing the structure to Trap().
  658. size_t size;
  659. // See the IPCZ_TRAP_* flags described above.
  660. IpczTrapConditionFlags flags;
  661. // See IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS. If that flag is not set in `flags`,
  662. // this field is ignord.
  663. size_t min_local_parcels;
  664. // See IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES. If that flag is not set in `flags`,
  665. // this field is ignored.
  666. size_t min_local_bytes;
  667. // See IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS. If that flag is not set in `flags`,
  668. // this field is ignored.
  669. size_t max_remote_parcels;
  670. // See IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES. If that flag is not set in `flags`,
  671. // this field is ignored.
  672. size_t max_remote_bytes;
  673. };
  674. // Structure passed to each IpczTrapEventHandler invocation with details about
  675. // the event.
  676. struct IPCZ_ALIGN(8) IpczTrapEvent {
  677. // The size of this structure in bytes. Populated by ipcz to indicate which
  678. // version is being provided to the handler.
  679. size_t size;
  680. // The context value that was given to Trap() when installing the trap that
  681. // fired this event.
  682. uintptr_t context;
  683. // Flags indicating which condition(s) triggered this event.
  684. IpczTrapConditionFlags condition_flags;
  685. // The current status of the portal which triggered this event. This address
  686. // is only valid through the extent of the event handler invocation.
  687. const struct IpczPortalStatus* status;
  688. };
  689. // An application-defined function to be invoked by a trap when its observed
  690. // conditions are satisfied on the monitored portal.
  691. typedef void(IPCZ_API* IpczTrapEventHandler)(const struct IpczTrapEvent* event);
  692. #if defined(__cplusplus)
  693. extern "C" {
  694. #endif
  695. // Table of API functions defined by ipcz. Instances of this structure may be
  696. // populated by passing them to an implementation of IpczGetAPIFn.
  697. //
  698. // Note that all functions follow a consistent parameter ordering:
  699. //
  700. // 1. Object handle (node or portal) if applicable
  701. // 2. Function-specific strict input values
  702. // 3. Flags - possibly untyped and unused
  703. // 4. Options struct - possibly untyped and unused
  704. // 5. Function-specific in/out values
  705. // 6. Function-specific strict output values
  706. //
  707. // The rationale behind this convention is generally to have order flow from
  708. // input to output. Flags are inputs, and options provide an extension point for
  709. // future versions of these APIs; as such they skirt the boundary between strict
  710. // input values and in/out values.
  711. //
  712. // The order and signature (ABI) of functions defined here must never change,
  713. // but new functions may be added to the end.
  714. struct IPCZ_ALIGN(8) IpczAPI {
  715. // The exact size of this structure in bytes. Must be set accurately by the
  716. // application before passing the structure to an implementation of
  717. // IpczGetAPIFn.
  718. size_t size;
  719. // Releases the object identified by `handle`. If it's a portal, the portal is
  720. // closed. If it's a node, the node is destroyed. If it's a wrapped driver
  721. // object, the object is released via the driver API's Close().
  722. //
  723. // This function is NOT thread-safe. It is the application's responsibility to
  724. // ensure that no other threads are performing other operations on `handle`
  725. // concurrently with this call or any time thereafter.
  726. //
  727. // Note that while closure is itself a (non-blocking) synchronous operation,
  728. // closure of various objects may have asynchronous side effects. For example,
  729. // closing a portal might asynchronously trigger a trap event on the portal's
  730. // remote peer.
  731. //
  732. // `flags` is ignored and must be 0.
  733. //
  734. // `options` is ignored and must be null.
  735. //
  736. // NOTE: If `handle` is a broker node in its cluster of connected nodes,
  737. // certain operations across the cluster -- such as driver object transmission
  738. // through portals or portal transference in general -- may begin to fail
  739. // spontaneously once destruction is complete.
  740. //
  741. // Returns:
  742. //
  743. // IPCZ_RESULT_OK if `handle` referred to a valid object and was
  744. // successfully closed by this operation.
  745. //
  746. // IPCZ_RESULT_INVALID_ARGUMENT if `handle` is invalid.
  747. IpczResult(IPCZ_API* Close)(IpczHandle handle, // in
  748. uint32_t flags, // in
  749. const void* options); // in
  750. // Initializes a new ipcz node. Applications typically need only one node in
  751. // each communicating process, but it's OK to create more. Practical use cases
  752. // for multiple nodes per process may include various testing scenarios, and
  753. // any situation where simulating a multiprocess environment is useful.
  754. //
  755. // All other ipcz calls are scoped to a specific node, or to a more specific
  756. // object which is itself scoped to a specific node.
  757. //
  758. // `driver` is the driver to use when coordinating internode communication.
  759. // Nodes which will be interconnected must use the same or compatible driver
  760. // implementations.
  761. //
  762. // `driver_node` is a driver-side handle to assign to the node throughout its
  763. // lifetime. This handle provides the driver with additional context when ipcz
  764. // makes driver API calls pertaining to a specific node. May be
  765. // IPCZ_INVALID_DRIVER_HANDLE if not used by the driver.
  766. //
  767. // If `flags` contains IPCZ_CREATE_NODE_AS_BROKER then the node will act as
  768. // the broker in its cluster of connected nodes. See details on that flag
  769. // description above.
  770. //
  771. // `options` is ignored and must be null.
  772. //
  773. // Returns:
  774. //
  775. // IPCZ_RESULT_OK if a new node was created. In this case, `*node` is
  776. // populated with a valid node handle upon return.
  777. //
  778. // IPCZ_RESULT_INVALID_ARGUMENT if `node` is null, or `driver` is null or
  779. // invalid.
  780. //
  781. // IPCZ_RESULT_UNIMPLEMENTED if some condition of the runtime environment
  782. // or architecture-specific details of the ipcz build would prevent it
  783. // from operating correctly. For example, the is returned if ipcz was
  784. // built against a std::atomic implementation which does not provide
  785. // lock-free 32-bit and 64-bit atomics.
  786. IpczResult(IPCZ_API* CreateNode)(const struct IpczDriver* driver, // in
  787. IpczDriverHandle driver_node, // in
  788. IpczCreateNodeFlags flags, // in
  789. const void* options, // in
  790. IpczHandle* node); // out
  791. // Connects `node` to another node in the system using an application-provided
  792. // driver transport handle in `driver_transport` for communication. If this
  793. // call will succeed, ipcz will call back into the driver to activate this
  794. // transport via ActivateTransport() before returning.
  795. //
  796. // The application is responsible for delivering the other endpoint of the
  797. // transport to whatever other node will use it with its own corresponding
  798. // ConnectNode() call.
  799. //
  800. // The calling node opens a number of initial portals (given by
  801. // `num_initial_portals`) linked to corresponding initial portals on the
  802. // remote node as soon as a two-way connection is fully established.
  803. //
  804. // Establishment of this connection is typically asynchronous, but this
  805. // depends on the driver implementation. In any case, the initial portals are
  806. // created and returned synchronously and can be used immediately by the
  807. // application. If the remote node issues a corresponding ConnectNode() call
  808. // with a smaller `num_initial_portals`, the excess portals created by this
  809. // node will behave as if their peer has been closed. On the other hand if the
  810. // remote node gives a larger `num_initial_portals`, then its own excess
  811. // portals will behave as if their peer has been closed.
  812. //
  813. //
  814. // If IPCZ_CONNECT_NODE_TO_BROKER is given in `flags`, the remote node must
  815. // be a broker node, and the calling node will treat it as such. If the
  816. // calling node is also a broker, the brokers' respective networks will be
  817. // effectively merged as long as both brokers remain alive: nodes in one
  818. // network will be able to discover and communicate directly with nodes in the
  819. // other network. Note that when two networks are merged, each broker remains
  820. // as the only broker within its own network; but brokers share enough
  821. // information to allow for discovery and interconnection of nodes between
  822. // networks.
  823. //
  824. // Conversely if IPCZ_CONNECT_NODE_TO_BROKER is *not* given and neither the
  825. // local nor remote nodes is a broker, one of the two nodes MUST NOT have a
  826. // broker yet and must specify IPCZ_CONNECT_NODE_INHERIT_BROKER in its
  827. // ConnectNode() call. The other node MUST have a broker already and it must
  828. // specify IPCZ_CONNECT_NODE_SHARE_BROKER in its own corresponding
  829. // ConnectNode() call.
  830. //
  831. // If IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE is given in `flags`, the
  832. // calling node delegates all ipcz internal shared memory allocation
  833. // operations to the remote node. This flag should only be used when the
  834. // calling node is operating in a restricted environment where direct shared
  835. // memory allocation is not possible.
  836. //
  837. // Returns:
  838. //
  839. // IPCZ_RESULT_OK if all arguments were valid and connection was initiated.
  840. // `num_initial_portals` portal handles are populated in
  841. // `initial_portals`. These may be used immediately by the application.
  842. //
  843. // Note that because the underlying connection may be established
  844. // asynchronously (depending on the driver implementation), this
  845. // operation may still fail after returning this value. If this
  846. // happens, all of the returned initial portals will behave as if their
  847. // peer has been closed.
  848. //
  849. // IPCZ_RESULT_INVALID_ARGUMENT if `node` is invalid, `num_initial_portals`
  850. // is zero, `initial_portals` is null, or `flags` specifies one or more
  851. // flags which are invalid for `node` or invalid when combined.
  852. //
  853. // IPCZ_RESULT_OUT_OF_RANGE if `num_initial_portals` is larger than the
  854. // ipcz implementation allows. There is no hard limit specified, but
  855. // any ipcz implementation must support at least 8 initial portals.
  856. IpczResult(IPCZ_API* ConnectNode)(IpczHandle node, // in
  857. IpczDriverHandle driver_transport, // in
  858. size_t num_initial_portals, // in
  859. IpczConnectNodeFlags flags, // in
  860. const void* options, // in
  861. IpczHandle* initial_portals); // out
  862. // Opens two new portals which exist as each other's opposite.
  863. //
  864. // Data and handles can be put in a portal with put operations (see Put(),
  865. // BeginPut(), EndPut()). Anything placed into a portal can be retrieved in
  866. // the same order by get operations (Get(), BeginGet(), EndGet()) on the
  867. // opposite portal.
  868. //
  869. // To open portals which span two different nodes at creation time, see
  870. // ConnectNode().
  871. //
  872. // `flags` is ignored and must be 0.
  873. //
  874. // `options` is ignored and must be null.
  875. //
  876. // Returns:
  877. //
  878. // IPCZ_RESULT_OK if portal creation was successful. `*portal0` and
  879. // `*portal1` are each populated with opaque portal handles which
  880. // identify the new pair of portals. The new portals are each other's
  881. // opposite and are entangled until one of them is closed.
  882. //
  883. // IPCZ_RESULT_INVALID_ARGUMENT if `node` is invalid, or if either
  884. // `portal0` or `portal1` is null.
  885. IpczResult(IPCZ_API* OpenPortals)(IpczHandle node, // in
  886. uint32_t flags, // in
  887. const void* options, // in
  888. IpczHandle* portal0, // out
  889. IpczHandle* portal1); // out
  890. // Merges two portals into each other, effectively destroying both while
  891. // linking their respective peer portals with each other. A portal cannot
  892. // merge with its own peer, and a portal cannot be merged into another if one
  893. // or more parcels have already been put into or taken out of either of them.
  894. // There are however no restrictions on what can be done to the portal's peer
  895. // prior to merging the portal with another.
  896. //
  897. // If we have two portal pairs:
  898. //
  899. // A ---- B and C ---- D
  900. //
  901. // some parcels are placed into A, and some parcels are placed into D, and
  902. // then we merge B with C, the net result will be a single portal pair:
  903. //
  904. // A ---- D
  905. //
  906. // All past and future parcels placed into A will arrive at D, and vice versa.
  907. //
  908. // `flags` is ignored and must be 0.
  909. //
  910. // `options` is ignored and must be null.
  911. //
  912. // Returns:
  913. //
  914. // IPCZ_RESULT_OK if the two portals were merged successfully. Neither
  915. // handle is valid past this point. Parcels now travel between the
  916. // merged portals' respective peers, including any parcels that were
  917. // in flight or queued at the time of this merge.
  918. //
  919. // IPCZ_RESULT_INVALID_ARGUMENT if `first` or `second` is invalid, if
  920. // `first` and `second` are each others' peer, or `first` and `second`
  921. // refer to the same portal.
  922. //
  923. // IPCZ_RESULT_FAILED_PRECONDITION if either `first` or `second` has
  924. // already had one or more parcels put into or gotten out of them.
  925. IpczResult(IPCZ_API* MergePortals)(IpczHandle first, // in
  926. IpczHandle second, // in
  927. uint32_t flags, // in
  928. const void* options); // out
  929. // Queries specific details regarding the status of a portal, such as the
  930. // number of unread parcels or data bytes available on the portal or its
  931. // opposite, or whether the opposite portal has already been closed.
  932. //
  933. // Note that because the portal's status is inherently dynamic and may be
  934. // modified at any time by any thread in any process with a handle to either
  935. // the portal or its opposite, the information returned in `status` may be
  936. // stale by the time a successful QueryPortalStatus() call returns.
  937. //
  938. // `flags` is ignored and must be 0.
  939. //
  940. // `options` is ignored and must be null.
  941. //
  942. // Returns:
  943. //
  944. // IPCZ_RESULT_OK if the requested query was completed successfully.
  945. // `status` is populated with details.
  946. //
  947. // IPCZ_RESULT_INVALID_ARGUMENT `portal` is invalid. `status` is null or
  948. // invalid.
  949. IpczResult(IPCZ_API* QueryPortalStatus)(
  950. IpczHandle portal, // in
  951. uint32_t flags, // in
  952. const void* options, // in
  953. struct IpczPortalStatus* status); // out
  954. // Puts any combination of data and handles into the portal identified by
  955. // `portal`. Everything put into a portal can be retrieved in the same order
  956. // by a corresponding get operation on the opposite portal. Depending on the
  957. // driver and the state of the relevant portals, the data and handles may
  958. // be delivered and retreivable immediately by the remote portal, or they may
  959. // be delivered asynchronously.
  960. //
  961. // `flags` is unused and must be IPCZ_NO_FLAGS.
  962. //
  963. // `options` may be null.
  964. //
  965. // If this call fails (returning anything other than IPCZ_RESULT_OK), any
  966. // provided handles remain property of the caller. If it succeeds, their
  967. // ownership is assumed by ipcz.
  968. //
  969. // Data to be submitted is read directly from the address given by the `data`
  970. // argument, and `num_bytes` specifies how many bytes of data to copy from
  971. // there.
  972. //
  973. // Callers may wish to request a view directly into portal memory for direct
  974. // writing. In such cases, a two-phase put operation can be used instead, by
  975. // calling BeginPut() and EndPut() as defined below.
  976. //
  977. // Returns:
  978. //
  979. // IPCZ_RESULT_OK if the provided data and handles were successfull placed
  980. // into the portal as a new parcel.
  981. //
  982. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `data` is null but
  983. // `num_bytes` is non-zero, `handles` is null but `num_handles` is
  984. // non-zero, `options` is non-null but invalid, one of the handles in
  985. // `handles` is equal to `portal` or its (local) opposite if
  986. // applicable, or if any handle in `handles` is invalid or not
  987. // serializable.
  988. //
  989. // IPCZ_RESULT_RESOURCE_EXHAUSTED if `options->limits` is non-null and at
  990. // least one of the specified limits would be violated by the
  991. // successful completion of this call.
  992. //
  993. // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
  994. // already been closed and anything put into this portal would be lost.
  995. IpczResult(IPCZ_API* Put)(IpczHandle portal, // in
  996. const void* data, // in
  997. size_t num_bytes, // in
  998. const IpczHandle* handles, // in
  999. size_t num_handles, // in
  1000. uint32_t flags, // in
  1001. const struct IpczPutOptions* options); // in
  1002. // Begins a two-phase put operation on `portal`. While a two-phase put
  1003. // operation is in progress on a portal, any other BeginPut() call on the same
  1004. // portal will fail with IPCZ_RESULT_ALREADY_EXISTS.
  1005. //
  1006. // Unlike a plain Put() call, two-phase put operations allow the application
  1007. // to write directly into portal memory, potentially reducing memory access
  1008. // costs by eliminating redundant copying and caching.
  1009. //
  1010. // The input value of `*num_bytes` tells ipcz how much data the caller would
  1011. // like to place into the portal.
  1012. //
  1013. // Limits provided to BeginPut() elicit similar behavior to Put(), with the
  1014. // exception that `flags` may specify IPCZ_BEGIN_PUT_ALLOW_PARTIAL to allow
  1015. // BeginPut() to succeed even the caller's suggested value of
  1016. // `*num_bytes` would cause the portal to exceed the maximum queued byte limit
  1017. // given by `options->limits`. In that case BeginPut() may update `*num_bytes`
  1018. // to reflect the remaining capacity of the portal, allowing the caller to
  1019. // commit at least some portion of their data with EndPut().
  1020. //
  1021. // Handles for two-phase puts are only provided when finalizing the operation
  1022. // with EndPut().
  1023. //
  1024. // Returns:
  1025. //
  1026. // IPCZ_RESULT_OK if the two-phase put operation has been successfully
  1027. // initiated. This operation must be completed with EndPut() before any
  1028. // further Put() or BeginPut() calls are allowed on `portal`. `*data`
  1029. // is set to the address of a portal buffer into which the application
  1030. // may copy its data, and `*num_bytes` is updated to reflect the
  1031. // capacity of that buffer, which may be greater than (or less than, if
  1032. // and only if IPCZ_BEGIN_PUT_ALLOW_PARTIAL was set in `flags`) the
  1033. // capacity requested by the input value of `*num_bytes`.
  1034. //
  1035. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `*num_bytes` is
  1036. // non-zero but `data` is null, or options is non-null and invalid.
  1037. //
  1038. // IPCZ_RESULT_RESOURCE_EXHAUSTED if completing the put with the number of
  1039. // bytes specified by `*num_bytes` would cause the portal to exceed the
  1040. // queued parcel limit or (if IPCZ_BEGIN_PUT_ALLOW_PARTIAL is not
  1041. // specified in `flags`) data byte limit specified by
  1042. // `options->limits`.
  1043. //
  1044. // IPCZ_RESULT_ALREADY_EXISTS if there is already a two-phase put operation
  1045. // in progress on `portal`.
  1046. //
  1047. // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
  1048. // already been closed and anything put into this portal would be lost.
  1049. IpczResult(IPCZ_API* BeginPut)(
  1050. IpczHandle portal, // in
  1051. IpczBeginPutFlags flags, // in
  1052. const struct IpczBeginPutOptions* options, // in
  1053. size_t* num_bytes, // out
  1054. void** data); // out
  1055. // Ends the two-phase put operation started by the most recent successful call
  1056. // to BeginPut() on `portal`.
  1057. //
  1058. // `num_bytes_produced` specifies the number of bytes actually written into
  1059. // the buffer that was returned from the original BeginPut() call.
  1060. //
  1061. // Usage of `handles` and `num_handles` is identical to Put().
  1062. //
  1063. // If this call fails (returning anything other than IPCZ_RESULT_OK), any
  1064. // provided handles remain property of the caller. If it succeeds, their
  1065. // ownership is assumed by ipcz.
  1066. //
  1067. // If IPCZ_END_PUT_ABORT is given in `flags` and there is a two-phase put
  1068. // operation in progress on `portal`, all other arguments are ignored and the
  1069. // pending two-phase put operation is cancelled without committing a new
  1070. // parcel to the portal.
  1071. //
  1072. // If EndPut() fails for any reason other than
  1073. // IPCZ_RESULT_FAILED_PRECONDITION, the two-phase put operation remains in
  1074. // progress, and EndPut() must be called again to abort the operation or
  1075. // attempt completion with different arguments.
  1076. //
  1077. // `options` is unused and must be null.
  1078. //
  1079. // Returns:
  1080. //
  1081. // IPCZ_RESULT_OK if the two-phase operation was successfully completed or
  1082. // aborted. If not aborted all data and handles were committed to a new
  1083. // parcel enqueued for retrieval by the opposite portal.
  1084. //
  1085. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `num_handles` is
  1086. // non-zero but `handles` is null, `num_bytes_produced` is larger than
  1087. // the capacity of the buffer originally returned by BeginPut(), or any
  1088. // handle in `handles` is invalid or not serializable.
  1089. //
  1090. // IPCZ_RESULT_FAILED_PRECONDITION if there was no two-phase put operation
  1091. // in progress on `portal`.
  1092. //
  1093. // IPCZ_RESULT_NOT_FOUND if it is known that the opposite portal has
  1094. // already been closed and anything put into this portal would be lost.
  1095. IpczResult(IPCZ_API* EndPut)(IpczHandle portal, // in
  1096. size_t num_bytes_produced, // in
  1097. const IpczHandle* handles, // in
  1098. size_t num_handles, // in
  1099. IpczEndPutFlags flags, // in
  1100. const void* options); // in
  1101. // Retrieves some combination of data and handles from a portal, as placed by
  1102. // a prior put operation on the opposite portal.
  1103. //
  1104. // On input, the values pointed to by `num_bytes` and `num_handles` must
  1105. // specify the capacity of each corresponding buffer argument. A null pointer
  1106. // implies zero capacity. It is an error to specify non-zero capacity if the
  1107. // corresponding buffer (`data` or `handles`) is null.
  1108. //
  1109. // Normally the data consumed by this call is copied directly to the address
  1110. // given by the `data` argument, and `*num_bytes` specifies how many bytes of
  1111. // storage are available there. If an application wishes to read directly
  1112. // from portal memory instead, a two-phase get operation can be used by
  1113. // calling BeginGet() and EndGet() as defined below.
  1114. //
  1115. // Note that if the caller does not provide enough storage capacity for a
  1116. // complete parcel and does not specify IPCZ_GET_PARTIAL in `flags`, this
  1117. // returns IPCZ_RESULT_RESOURCE_EXHAUSTED and outputs the actual capacity
  1118. // required for the message without copying any of its contents. See details
  1119. // of that return value below.
  1120. //
  1121. // If IPCZ_GET_PARTIAL is specified, the call succeeds as long as a parcel is
  1122. // available, and the caller retrieves as much data and handles as their
  1123. // expressed capacity will allow. In this case, the in/out capacity arguments
  1124. // (`num_bytes` and `num_handles`) are still updated as specified in the
  1125. // IPCZ_RESULT_OK details below.
  1126. //
  1127. // `options` is ignored and must be null.
  1128. //
  1129. // Returns:
  1130. //
  1131. // IPCZ_RESULT_OK if there was a parcel available in the portal's queue and
  1132. // its data and handles were able to be copied into the caller's
  1133. // provided buffers. In this case values pointed to by `num_bytes` and
  1134. // `num_handles` (for each one that is non-null) are updated to reflect
  1135. // what was actually consumed. Note that the caller assumes ownership
  1136. // of all returned handles.
  1137. //
  1138. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `data` is null but
  1139. // `*num_bytes` is non-zero, or `handles` is null but `*num_handles` is
  1140. // non-zero.
  1141. //
  1142. // IPCZ_RESULT_RESOURCE_EXHAUSTED if the next available parcel would exceed
  1143. // the caller's specified capacity for either data bytes or handles,
  1144. // and IPCZ_GET_PARTIAL was not specified in `flags`. In this case, any
  1145. // non-null size pointer is updated to convey the minimum capacity that
  1146. // would have been required for an otherwise identical Get() call to
  1147. // have succeeded. Callers observing this result may wish to allocate
  1148. // storage accordingly and retry with updated parameters.
  1149. //
  1150. // IPCZ_RESULT_UNAVAILABLE if the portal's parcel queue is currently empty.
  1151. // In this case callers should wait before attempting to get anything
  1152. // from the same portal again.
  1153. //
  1154. // IPCZ_RESULT_NOT_FOUND if there are no more parcels in the portal's queue
  1155. // AND the opposite portal is known to be closed. If this result is
  1156. // returned, no parcels can ever be read from this portal again.
  1157. //
  1158. // IPCZ_RESULT_ALREADY_EXISTS if there is a two-phase get operation in
  1159. // progress on `portal`.
  1160. IpczResult(IPCZ_API* Get)(IpczHandle portal, // in
  1161. IpczGetFlags flags, // in
  1162. const void* options, // in
  1163. void* data, // out
  1164. size_t* num_bytes, // in/out
  1165. IpczHandle* handles, // out
  1166. size_t* num_handles); // in/out
  1167. // Begins a two-phase get operation on `portal` to retrieve data and handles.
  1168. // While a two-phase get operation is in progress on a portal, all other get
  1169. // operations on the same portal will fail with IPCZ_RESULT_ALREADY_EXISTS.
  1170. //
  1171. // Unlike a plain Get() call, two-phase get operations allow the application
  1172. // to read directly from portal memory, potentially reducing memory access
  1173. // costs by eliminating redundant copying and caching.
  1174. //
  1175. // If `data` or `num_bytes` is null and the available parcel has at least one
  1176. // byte of data, or if there are handles present but `num_handles` is null,
  1177. // this returns IPCZ_RESULT_RESOURCE_EXHAUSTED.
  1178. //
  1179. // Otherwise a successful BeginGet() updates values pointed to by `data`,
  1180. // `num_bytes`, and `num_handles` to convey the parcel's data storage and
  1181. // capacity as well as the capacity required to read out any handles.
  1182. //
  1183. // NOTE: When performing two-phase get operations, callers should be mindful
  1184. // of time-of-check/time-of-use (TOCTOU) vulnerabilities. Exposed parcel
  1185. // memory may be shared with (and writable in) the process which placed the
  1186. // parcel into the portal, and that process may not be trustworthy. In such
  1187. // cases, applications should be careful to copy the data out before
  1188. // validating and using it.
  1189. //
  1190. // `flags` is ignored and must be IPCZ_NO_FLAGS.
  1191. //
  1192. // `options` is ignored and must be null.
  1193. //
  1194. // Returns:
  1195. //
  1196. // IPCZ_RESULT_OK if the two-phase get was successfully initiated. In this
  1197. // case both `*data` and `*num_bytes` are updated (if `data` and
  1198. // `num_bytes` were non-null) to describe the portal memory from which
  1199. // the application is free to read parcel data. If `num_handles` is
  1200. // is non-null, the value pointed to is updated to reflect the number
  1201. // of handles available to retrieve.
  1202. //
  1203. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid.
  1204. //
  1205. // IPCZ_RESULT_RESOURCE_EXHAUSTED if the next available parcel has at least
  1206. // one data byte but `data` or `num_bytes` is null; or if the parcel
  1207. // has any handles but `num_handles` null.
  1208. //
  1209. // IPCZ_RESULT_UNAVAILABLE if the portal's parcel queue is currently empty.
  1210. // In this case callers should wait before attempting to get anything
  1211. // from the same portal again.
  1212. //
  1213. // IPCZ_RESULT_NOT_FOUND if there are no more parcels in the portal's queue
  1214. // AND the opposite portal is known to be closed. In this case, no get
  1215. // operation can ever succeed again on this portal.
  1216. //
  1217. // IPCZ_RESULT_ALREADY_EXISTS if there is already a two-phase get operation
  1218. // in progress on `portal`.
  1219. IpczResult(IPCZ_API* BeginGet)(IpczHandle portal, // in
  1220. uint32_t flags, // in
  1221. const void* options, // in
  1222. const void** data, // out
  1223. size_t* num_bytes, // out
  1224. size_t* num_handles); // out
  1225. // Ends the two-phase get operation started by the most recent successful call
  1226. // to BeginGet() on `portal`.
  1227. //
  1228. // `num_bytes_consumed` specifies the number of bytes actually read from the
  1229. // buffer that was returned from the original BeginGet() call. `num_handles`
  1230. // specifies the capacity of `handles` and must be no larger than the
  1231. // capacity indicated by the corresponding output from BeginGet().
  1232. //
  1233. // If IPCZ_END_GET_ABORT is given in `flags` and there is a two-phase get
  1234. // operation in progress on `portal`, all other arguments are ignored and the
  1235. // pending operation is cancelled without consuming any data from the portal.
  1236. //
  1237. // `options` is unused and must be null.
  1238. //
  1239. // Returns:
  1240. //
  1241. // IPCZ_RESULT_OK if the two-phase operation was successfully completed or
  1242. // aborted. Note that if the frontmost parcel wasn't fully consumed by
  1243. // the caller, it will remain in queue with the rest of its data intact
  1244. // for a subsequent get operation to retrieve. Exactly `num_handles`
  1245. // handles will be copied into `handles`.
  1246. //
  1247. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, or if `num_handles`
  1248. // is non-zero but `handles` is null.
  1249. //
  1250. // IPCZ_RESULT_OUT_OF_RANGE if either `num_bytes_consumed` or `num_handles`
  1251. // is larger than the capacity returned by BeginGet().
  1252. //
  1253. // IPCZ_RESULT_FAILED_PRECONDITION if there was no two-phase get operation
  1254. // in progress on `portal`.
  1255. IpczResult(IPCZ_API* EndGet)(IpczHandle portal, // in
  1256. size_t num_bytes_consumed, // in
  1257. size_t num_handles, // in
  1258. IpczEndGetFlags flags, // in
  1259. const void* options, // in
  1260. IpczHandle* handles); // out
  1261. // Attempts to install a trap to catch interesting changes to a portal's
  1262. // state. The condition(s) to observe are specified in `conditions`.
  1263. // Regardless of what conditions the caller specifies, all successfully
  1264. // installed traps also implicitly observe IPCZ_TRAP_REMOVED.
  1265. //
  1266. // If successful, ipcz guarantees that `handler` will be invoked -- with the
  1267. // the `context` field of the invocation's IpczTrapEvent reflecting the value
  1268. // of `context` given here -- once any of the specified conditions have been
  1269. // met.
  1270. //
  1271. // Immediately before invoking its handler, the trap is removed from the
  1272. // portal and must be reinstalled in order to observe further state changes.
  1273. //
  1274. // When a portal is closed, any traps still installed on it are notified by
  1275. // invoking their handler with IPCZ_TRAP_REMOVED in the event's
  1276. // `condition_flags`. This effectively guarantees that all installed traps
  1277. // eventually see a handler invocation.
  1278. //
  1279. // Note that `handler` may be invoked from any thread that can modify the
  1280. // state of the observed portal. This is limited to threads which make direct
  1281. // ipcz calls on the portal, and any threads on which the portal's node may
  1282. // receive notifications from a driver transport.
  1283. //
  1284. // If any of the specified conditions are already met, the trap is not
  1285. // installed and this call returns IPCZ_RESULT_FAILED_PRECONDITION. See below
  1286. // for details.
  1287. //
  1288. // `flags` is ignored and must be 0.
  1289. //
  1290. // `options` is ignored and must be null.
  1291. //
  1292. // Returns:
  1293. //
  1294. // IPCZ_RESULT_OK if the trap was installed successfully. In this case
  1295. // `flags` and `status` arguments are ignored.
  1296. //
  1297. // IPCZ_RESULT_INVALID_ARGUMENT if `portal` is invalid, `conditions` is
  1298. // null or invalid, `handler` is null, or `status` is non-null but its
  1299. // `size` field specifies an invalid value.
  1300. //
  1301. // IPCZ_RESULT_FAILED_PRECONDITION if the conditions specified are already
  1302. // met on the portal. If `satisfied_condition_flags` is non-null, then
  1303. // its pointee value will be updated to reflect the flags in
  1304. // `conditions` which were already satisfied by the portal's state. If
  1305. // `status` is non-null, a copy of the portal's last known status will
  1306. // also be stored there.
  1307. IpczResult(IPCZ_API* Trap)(
  1308. IpczHandle portal, // in
  1309. const struct IpczTrapConditions* conditions, // in
  1310. IpczTrapEventHandler handler, // in
  1311. uintptr_t context, // in
  1312. uint32_t flags, // in
  1313. const void* options, // in
  1314. IpczTrapConditionFlags* satisfied_condition_flags, // out
  1315. struct IpczPortalStatus* status); // out
  1316. // Boxes an object managed by a node's driver and returns a new IpczHandle to
  1317. // reference the box. If the driver is able to serialize the boxed object, the
  1318. // box can be placed into a portal for transmission to the other side.
  1319. //
  1320. // Boxes can be sent through portals along with other IpczHandles, effectively
  1321. // allowing drivers to introduce new types of transferrable objects via boxes.
  1322. //
  1323. // `flags` is ignored and must be 0.
  1324. //
  1325. // `options` is ignored and must be null.
  1326. //
  1327. // Returns:
  1328. //
  1329. // IPCZ_RESULT_OK if the driver handle was boxed and a new IpczHandle is
  1330. // returned in `handle`.
  1331. //
  1332. // IPCZ_RESULT_INVALID_ARGUMENT if `driver_handle` was invalid.
  1333. IpczResult(IPCZ_API* Box)(IpczHandle node, // in
  1334. IpczDriverHandle driver_handle, // in
  1335. uint32_t flags, // in
  1336. const void* options, // in
  1337. IpczHandle* handle); // out
  1338. // Unboxes a driver object from an IpczHandle previously produced by Box().
  1339. //
  1340. // `flags` is ignored and must be 0.
  1341. //
  1342. // `options` is ignored and must be null.
  1343. //
  1344. // Returns:
  1345. //
  1346. // IPCZ_RESULT_OK if the driver object was successfully unboxed. A driver
  1347. // handle to the object is placed in `*driver_handle`.
  1348. //
  1349. // IPCZ_RESULT_INVALID_ARGUMENT if `handle` is invalid or does not
  1350. // reference a box.
  1351. IpczResult(IPCZ_API* Unbox)(IpczHandle handle, // in
  1352. IpczUnboxFlags flags, // in
  1353. const void* options, // in
  1354. IpczDriverHandle* driver_handle); // out
  1355. };
  1356. // A function which populates `api` with a table of ipcz API functions. The
  1357. // `size` field must be set by the caller to the size of the structure before
  1358. // issuing this call.
  1359. //
  1360. // In practice ipcz defines IpczGetAPI() as an implementation of this function
  1361. // type. How applications acquire a reference to that function depends on how
  1362. // the application builds and links against ipcz.
  1363. //
  1364. // Upon return, `api->size` indicates the size of the function table actually
  1365. // populated and therefore which version of the ipcz implementation is in use.
  1366. // Note that this size will never exceed the input value of `api->size`: if the
  1367. // caller is built against an older version than what is available, the
  1368. // available implementation will only populate the functions appropriate for
  1369. // that older version. Conversely if the caller is built against a newer version
  1370. // than what is available, `api->size` on output may be smaller than its value
  1371. // was on input.
  1372. //
  1373. // Returns:
  1374. //
  1375. // IPCZ_RESULT_OK if `api` was successfully populated. In this case
  1376. // `api->size` effectively indicates the API version provided, and the
  1377. // appropriate function pointers within `api` are filled in.
  1378. //
  1379. // IPCZ_RESULT_INVALID_ARGUMENT if `api` is null or the caller's provided
  1380. // `api->size` is less than the size of the function table required to
  1381. // host API version 0.
  1382. typedef IpczResult(IPCZ_API* IpczGetAPIFn)(struct IpczAPI* api);
  1383. #if defined(__cplusplus)
  1384. } // extern "C"
  1385. #endif
  1386. #endif // IPCZ_INCLUDE_IPCZ_IPCZ_H_