1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
|
/**
* # Arti RPC core library header.
*
* (TODO RPC: This is still a work in progress; please don't rely on it
* being the final API.)
*
* ## What this library does
*
* The Arti RPC system works by establishing connections to an Arti instance,
* and then exchanging requests and replies in a format inspired by
* JSON-RPC. This library takes care of the work of connecting to an Arti
* instance, authenticating, validating outgoing JSON requests, and matching
* their corresponding JSON responses as they arrive.
*
* This library _does not_ do the work of creating well-formed requests,
* or interpreting the responses.
*
* (Note: Despite this library being exposed via a set of C functions,
* we don't actually expect you to use it from C. It's probably a better
* idea to wrap it in a higher-level language and then use it from there.)
*
* ## Using this library
*
* TODO RPC Explain better.
*
* Your connection to Arti is represented by an `ArtiRpcConn *`. Use
* `arti_rpc_connect()` to create one of these.
*
* Once you have a connection, you can sent Arti various requests in
* JSON format. See (TODO RPC: Add a link to a list of comments.)
* Use `arti_rpc_execute()` to send a simple request; the function will
* return when the request succeeds, or fails.
*
* TODO: Explain handles and other APIs once I add those APIs.
*
* Except when noted otherwise, all functions in this library are thread-safe.
*
* ## Error handling
*
* On success, fallible functions return `ARTI_RPC_STATUS_SUCCESS`. On failure,
* they return some other error code, and set an `* error_out` parameter
* to a newly allocated `ArtiRpcError` object.
* (If `error_out==NULL`, then no error is allocated.)
*
* You can access information about the an `ArtiRpcError`
* by calling `arti_rpc_err_{status,message,response}()` on it.
* When you are done with an error, you should free it with
* `arti_rpc_err_free()`.
*
* The `error_out` parameter always appears last.
*
* ## Interface conventions
*
* - All functions check for NULL pointers in their arguments.
* - As in C tor, `foo_free()` functions treat `foo_free(NULL)` as a no-op.
*
* - All input strings should be valid UTF-8. (The library will check.)
* All output strings will be valid UTF-8.
*
* - Fallible functions return an ArtiStatus.
*
* - All identifiers are prefixed with `ARTI_RPC`, `ArtiRpc`, or `arti_rpc` as appropriate.
*
* - Newly allocated objects are returned via out-parameters,
* with `out` in their names.
* (For example, `ArtiRpcObject **out`). In such cases, `* out` will be set to a resulting object,
* or to NULL if no such object is returned. Any earlier value of `*out` will be replaced
* without freeing it.
* (If `out` is NULL, then any object the library would have returned will instead be discareded.)
* discarded.
* While the function is running,
* `*out` and `**out` may not be read or written by any other part of the program,
* and they may not alias any other arguments.)
* - Note that `*out` will be set to NULL if an error occurs
* or the function's inputs are invalid.
* (The `*error_out` parameter, of course,
* is set to NULL when there is _no_ error, and to an error otherwise.)
*
* - When any object is exposed as a non-const pointer,
* the application becomes the owner of that object.
* The application is expected to eventually free that object via the corresponding `arti_rpc_*_free()` function.
*
* - When any object is exposed via a const pointer,
* that object is *not* owned by the application.
* That object's lifetime will be as documented.
* The application must not modify or free such an object.
*
* - If a function should be considered a method on a given type of object,
* it will take a pointer to that object as its first argument.
*
* - If a function consumes (takes ownership of) one of its inputs,
* it does so regardless of whether the function succeeds or fails.
*
* ## Correctness requirements
*
* If any correctness requirements stated here or elsewhere are violated,
* it is Undefined Behaviour.
* Violations will not be detected by the library.
*
* - Basic C rules apply:
* - If you pass a non-NULL pointer to a function, the pointer must be properly aligned.
* It must point to valid, initialized data of the correct type.
* - As an exception, functions that take a `Type **out` parameter allow the value of `*out`
* (but not `out` itself!) to be uninitialized.
* - If you receive data via a `const *`, you must not modify that data.
* - If you receive a pointer of type `struct Type *`,
* and we do not give you the definition of `struct Type`,
* you must not attempt to dereference the pointer.
* - You may not call any `_free()` function on an object that is currently in use.
* - After you have `_freed()` an object, you may not use it again.
* - Every object allocated by this library has a corresponding `*_free()` function:
* You must not use libc's free() to free such objects.
* - All objects passed as input to a library function must not be mutated
* while that function is running.
* - All objects passed as input to a library function via a non-const pointer
* must not be mutated, inspected, or passed to another library function
* while the function is running.
* - Furthermore, if a function takes any non-const pointer arguments,
* those arguments must not alias one another,
* and must not alias any const arguments passed to the function.
* - All `const char*` passed as inputs to library functions
* are nul-terminated strings.
* Additionally, they must be no larger than `SSIZE_MAX`,
including the nul.
* - If a function takes any mutable pointers
**/
#ifndef ARTI_RPC_CLIENT_CORE_H_
#define ARTI_RPC_CLIENT_CORE_H_
/* Automatically generated by cbindgen. Don't modify manually. */
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/**
* A string that is guaranteed to be UTF-8 and NUL-terminated,
* for fast access as either type.
*/
typedef struct Utf8CString Utf8CString;
/**
* A status code returned by an Arti RPC function.
*
* On success, a function will return `ARTI_SUCCESS (0)`.
* On failure, a function will return some other status code.
*/
typedef uint32_t ArtiRpcStatus;
/**
* An open connection to Arti over an a RPC protocol.
*
* This is a thread-safe type: you may safely use it from multiple threads at once.
*
* Once you are no longer going to use this connection at all, you must free
* it with [`arti_rpc_conn_free`]
*/
typedef struct ArtiRpcConn ArtiRpcConn;
/**
* An error returned by the Arti RPC code, exposed as an object.
*
* When a function returns an [`ArtiRpcStatus`] other than [`ARTI_RPC_STATUS_SUCCESS`],
* it will also expose a newly allocated value of this type
* via its `error_out` parameter.
*/
typedef struct ArtiRpcError ArtiRpcError;
/**
* An owned string, returned by this library.
*
* This string must be released with `arti_rpc_str_free`.
* You can inspect it with `arti_rpc_str_get`, but you may not modify it.
* The string is guaranteed to be UTF-8 and NUL-terminated.
*/
typedef struct Utf8CString ArtiRpcStr;
/**
* The function has returned successfully.
*/
#define ARTI_RPC_STATUS_SUCCESS 0
/**
* One or more of the inputs to a library function was invalid.
*
* (This error was generated by the library, before any request was sent.)
*/
#define ARTI_RPC_STATUS_INVALID_INPUT 1
/**
* Tried to use some functionality
* (for example, an authentication method or connection scheme)
* that wasn't available on this platform or build.
*
* (This error was generated by the library, before any request was sent.)
*/
#define ARTI_RPC_STATUS_NOT_SUPPORTED 2
/**
* Tried to connect to Arti, but an IO error occurred.
*
* This may indicate that Arti wasn't running,
* or that Arti was built without RPC support,
* or that Arti wasn't running at the specified location.
*
* (This error was generated by the library.)
*/
#define ARTI_RPC_STATUS_CONNECT_IO 3
/**
* We tried to authenticate with Arti, but it rejected our attempt.
*
* (This error was sent by the peer.)
*/
#define ARTI_RPC_STATUS_BAD_AUTH 4
/**
* Our peer has, in some way, violated the Arti-RPC protocol.
*
* (This error was generated by the library,
* based on a response from Arti that appeared to be invalid.)
*/
#define ARTI_RPC_STATUS_PEER_PROTOCOL_VIOLATION 5
/**
* The peer has closed our connection; possibly because it is shutting down.
*
* (This error was generated by the library,
* based on the connection being closed or reset from the peer.)
*/
#define ARTI_RPC_STATUS_SHUTDOWN 6
/**
* An internal error occurred in the arti rpc client.
*
* (This error was generated by the library.
* If you see it, there is probably a bug in the library.)
*/
#define ARTI_RPC_STATUS_INTERNAL 7
/**
* The peer reports that one of our requests has failed.
*
* (This error was sent by the peer, in response to one of our requests.
* No further responses to that request will be received or accepted.)
*/
#define ARTI_RPC_STATUS_REQUEST_FAILED 8
/**
* Tried to check the status of a request and found that it was no longer running.
*
* TODO RPC: We should make sure that this is the actual semantics we want for this
* error! Revisit after we have implemented real cancellation.
*/
#define ARTI_RPC_STATUS_REQUEST_CANCELLED 9
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Try to open a new connection to an Arti instance.
*
* The location of the instance and the method to connect to it are described in
* `connection_string`.
*
* (TODO RPC: Document the format of this string better!)
*
* On success, return `ARTI_RPC_STATUS_SUCCESS` and set `*rpc_conn_out` to a new ArtiRpcConn.
* Otherwise return some other status code, set `*rpc_conn_out` to NULL, and set
* `*error_out` (if provided) to a newly allocated error object.
*
*
* # Ownership
*
* The caller is responsible for making sure that `*rpc_conn_out` and `*error_out`,
* if set, are eventually freed.
*/
ArtiRpcStatus arti_rpc_connect(const char *connection_string,
ArtiRpcConn **rpc_conn_out,
ArtiRpcError **error_out);
/**
* Run an RPC request over `rpc_conn` and wait for a successful response.
*
* The message `msg` should be a valid RPC request in JSON format.
* If you omit its `id` field, one will be generated: this is typically the best way to use this function.
*
* On success, return `ARTI_RPC_STATUS_SUCCESS` and set `*response_out` to a newly allocated string
* containing the JSON response to your request (including `id` and `response` fields).
*
* Otherwise return some other status code, set `*response_out` to NULL,
* and set `*error_out` (if provided) to a newly allocated error object.
*
* (If response_out is set to NULL, then any successful response will be ignored.)
*
* # Ownership
*
* The caller is responsible for making sure that `*error_out`, if set, is eventually freed.
*/
ArtiRpcStatus arti_rpc_conn_execute(const ArtiRpcConn *rpc_conn,
const char *msg,
ArtiRpcStr **response_out,
ArtiRpcError **error_out);
/**
* Free a string returned by the Arti RPC API.
*/
void arti_rpc_str_free(ArtiRpcStr *string);
/**
* Return a const pointer to the underlying nul-terminated string from an `ArtiRpcStr`.
*
* The resulting string is guaranteed to be valid UTF-8.
*
* (Returns NULL if the input is NULL.)
*
* # Correctness requirements
*
* The resulting string pointer is valid only for as long as the input `string` is not freed.
*/
const char *arti_rpc_str_get(const ArtiRpcStr *string);
/**
* Close and free an open Arti RPC connection.
*/
void arti_rpc_conn_free(ArtiRpcConn *rpc_conn);
/**
* Return a string representing the meaning of a given `ArtiRpcStatus`.
*
* The result will always be non-NULL, even if the status is unrecognized.
*/
const char *arti_status_to_str(ArtiRpcStatus status);
/**
* Return the status code associated with a given error.
*
* If `err` is NULL, return [`ARTI_RPC_STATUS_INVALID_INPUT`].
*/
ArtiRpcStatus arti_rpc_err_status(const ArtiRpcError *err);
/**
* Return a human-readable error message associated with a given error.
*
* The format of these messages may change arbitrarily between versions of this library;
* it is a mistake to depend on the actual contents of this message.
*
* Return NULL if the input `err` is NULL.
*
* # Correctness requirements
*
* The resulting string pointer is valid only for as long as the input `err` is not freed.
*/
const char *arti_rpc_err_message(const ArtiRpcError *err);
/**
* Return a Json-formatted error response associated with a given error.
*
* These messages are full responses, including the `error` field,
* and the `id` field (if present).
*
* Return NULL if the specified error does not represent an RPC error response.
*
* Return NULL if the input `err` is NULL.
*
* # Correctness requirements
*
* The resulting string pointer is valid only for as long as the input `err` is not freed.
*/
const char *arti_rpc_err_response(const ArtiRpcError *err);
/**
* Make and return copy of a provided error.
*
* Return NULL if the input is NULL.
*
* # Ownership
*
* The caller is responsible for making sure that the returned object
* is eventually freed with `arti_rpc_err_free()`.
*/
ArtiRpcError *arti_rpc_err_clone(const ArtiRpcError *err);
/**
* Release storage held by a provided error.
*/
void arti_rpc_err_free(ArtiRpcError *err);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* ARTI_RPC_CLIENT_CORE_H_ */
|