libwebsockets
Lightweight C library for HTML5 websockets
lws-jrpc.h
Go to the documentation of this file.
1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 *
25 * This is a JSON-RPC parser and state management implementation that's:
26 *
27 * - Lightweight, it uses lws LEJP JSON stream parser for requests, responses,
28 * and user-defined parameter objects
29 *
30 * - Stateful... you can give it sequential input buffers randomly fragmented
31 * and it will complete when it has enough
32 *
33 * - Asynchronous... response processing can return to the event loop both
34 * while the RX is still coming and after it's all received before forming
35 * the response, eg, because it's querying on a remote connection to get the
36 * response data. Any number of RPCs can be either in flight or waiting for
37 * response processing to complete before responding.
38 *
39 * - Supports "version" extension
40 *
41 * - allows binding different method names to different callbacks
42 *
43 * - Supports both client and server roles, eg, can parse both requests and
44 * responses
45 *
46 * - No support for batch. Batching is not widely used because it doesn't
47 * add anything for the vast bulk of cases compared to sending n requests.
48 *
49 * This handles client and server RX and transaction state, creating a callback
50 * when parameters can be parsed and all of the request or notification is
51 * done.
52 *
53 * Producing JSON is usually simpler and more compact than expressing it as an
54 * object model, ie often a response can be completely formed in a single
55 * lws_snprintf(). Response JSON must be buffered on heap until the method
56 * callback is called with NULL / 0 buf len indicating that the incoming request
57 * has completed parsing.
58 *
59 */
60
61/* these are opaque */
62
63struct lws_jrpc_obj;
64struct lws_jrpc;
65
66typedef enum {
71} lws_jrpc_cb_return_t;
72
73/*
74 * method name to lejp parsing handler map
75 */
76
77typedef struct lws_jrpc_method {
78 const char *method_name;
79 const char * const *paths;
82} lws_jrpc_method_t;
83
84/*
85 * Boilerplate for forming correct requests
86 */
87
88/* Boilerplate to start a request */
89#define LWSJRPCBP_REQ_START_S "{\"jsonrpc\":\"2.0\",\"method\":\"%s\""
90/* Boilerplate to start parameters (params are left freeform for user) */
91#define LWSJRPCBP_REQ_VERSION_S ",\"version\":\"%s\""
92/* Boilerplate to start parameters (params are left freeform for user) */
93#define LWSJRPCBP_REQ_PARAMS ",\"params\":"
94/* Boilerplate to complete the result object */
95#define LWSJRPCBP_REQ_NOTIF_END "}"
96/* Boilerplate to complete the result object */
97#define LWSJRPCBP_REQ_ID_END_S ",\"id\":%s}"
98
99/*
100 * Boilerplate for forming correct responses
101 */
102
103/* Boilerplate to start a result */
104#define LWSJRPCBP_RESP_RESULT "{\"jsonrpc\":\"2.0\",\"result\":"
105/* Boilerplate to complete the result object */
106#define LWSJRPCBP_RESP_ID_END_S ",\"id\":%s}"
107
108/* Boilerplate to form an error */
109#define LWSJRPCBP_RESP_ERROR_D "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":%d"
110/* optional */
111#define LWSJRPCBP_RESP_ERROR_MSG_S ",\"message\":\"%s\""
112/* optional */
113#define LWSJRPCBP_RESP_ERROR_DATA ",\"data\":"
114/* required */
115#define LWSJRPCBP_RESP_ERROR_END "}"
116
117/*
118 * JSONRPC Well-known Errors
119 */
120
121enum {
123
124 LWSJRPCWKE__PARSE_ERROR = -32700, /* invalid JSON */
125 LWSJRPCWKE__INVALID_REQUEST = -32600, /* not valid JSONRPC object */
126 LWSJRPCWKE__METHOD_NOT_FOUND = -32601, /* method not supported */
127 LWSJRPCWKE__INVALID_PARAMS = -32602, /* parameters are invalid */
128 LWSJRPCWKE__INTERNAL_ERROR = -32603, /* internal JSONRPC error */
129 LWSJRPCWKE__SERVER_ERROR_FIRST = -32000, /* implementation-defined...*/
130 LWSJRPCWKE__SERVER_ERROR_LAST = -32099, /* ... server errors range */
131
132 LWSJRPCE__INVALID_MEMBERS = -31000, /* reponse membs in req, vv */
133};
134
135enum {
139
140/*
141 * APIs for the opaque JRPC request object
142 */
143
144/**
145 * lws_jrpc_obj_parse() - parse a request or response
146 *
147 * \param jrpc: the jrpc context this belongs to
148 * \param type: LWSJRPC_PARSE_REQUEST or ..._RESPONSE
149 * \param opaque: user-defined pointer bound to lws_jrpc, ignored by lws
150 * \param buf: chunk of JSON-RPC
151 * \param l: remaining length of JSON (may be under or oversize)
152 * \param r: NULL to indicate starting new req, already set means continue parse
153 *
154 * If necessary creates an opaque req object and starts parsing len bytes of
155 * buf. This may be undersize (more parts coming) in which case \p req will be
156 * set on entry next time indicating a continuation.
157 *
158 * \p type and \p opaque are ignored if it it's not the first buffer that
159 * creates the req object.
160 *
161 * Return code is >= 0 if completed, representing the amount of unused data in
162 * the input buffer. -1 indicates more input data needed, <-1 indicates an
163 * error from the LWSJRPCWKE_ set above, or LEJP_REJECT_UNKNOWN for OOM
164 */
165
166LWS_VISIBLE LWS_EXTERN int
167lws_jrpc_obj_parse(struct lws_jrpc *jrpc, int type, void *opaque,
168 const char *buf, size_t l, struct lws_jrpc_obj **r);
169
170/*
171 * lws_jrpc_obj_destroy() - detach and destroy a JRPC request or response
172 *
173 * \param _r: pointer to pointer to JRPC request to detach and free
174 *
175 * Detaches the req from its JRPC context and frees it and any internal
176 * allocations.
177 */
178LWS_VISIBLE LWS_EXTERN void
179lws_jrpc_obj_destroy(struct lws_jrpc_obj **_r);
180
181/*
182 * lws_jrpc_obj_get_opaque() - retreive the opaque pointer bound to the req
183 *
184 * \param r: pointer to pointer to JRPC request
185 *
186 * Returns the opaque pointer for a req given when it was parsed / created.
187 */
188LWS_VISIBLE LWS_EXTERN void *
189lws_jrpc_obj_get_opaque(const struct lws_jrpc_obj *r);
190
191/*
192 * lws_jrpc_obj_id() - retreive the object's id string
193 *
194 * \param r: pointer to pointer to JRPC object
195 *
196 * Returns a pointer to a correctly-typed id for use in a response; if a string,
197 * then it is already quoted, if an int or null then it's provided without
198 * quotes.
199 */
200LWS_VISIBLE LWS_EXTERN const char *
201lws_jrpc_obj_id(const struct lws_jrpc_obj *r);
202
203
204/*
205 * APIs for the opaque JRPC context
206 */
207
208/**
209 * lws_jrpc_create() - Allocate and initialize a JRPC context
210 *
211 * \param methods: the method callbacks and names we can process
212 * \param opaque: user-defined pointer bound to lws_jrpc ignored by lws
213 *
214 * Allocates an opaque lws_jrpc object and binds it to the given array of
215 * method names and callbacks
216 */
217LWS_VISIBLE LWS_EXTERN struct lws_jrpc *
218lws_jrpc_create(const lws_jrpc_method_t *methods, void *opaque);
219
220/*
221 * lws_jrpc_destroy() - destroy an allocated JRPC context
222 *
223 * \param jrpc: pointer to pointer to jrpc to destroy
224 *
225 * Destroys any ongoing reqs in the JRPC and then destroys the JRPC and sets the
226 * given pointer to NULL.
227 */
228LWS_VISIBLE LWS_EXTERN void
229lws_jrpc_destroy(struct lws_jrpc **jrpc);
LWS_VISIBLE LWS_EXTERN const char * lws_jrpc_obj_id(const struct lws_jrpc_obj *r)
@ LJRPC_CBRET_CONTINUE
Definition: lws-jrpc.h:67
@ LJRPC_CBRET_FAILED
Definition: lws-jrpc.h:70
@ LJRPC_CBRET_WANT_TO_EMIT
Definition: lws-jrpc.h:68
@ LJRPC_CBRET_FINISHED
Definition: lws-jrpc.h:69
LWS_VISIBLE LWS_EXTERN struct lws_jrpc * lws_jrpc_create(const lws_jrpc_method_t *methods, void *opaque)
LWS_VISIBLE LWS_EXTERN void * lws_jrpc_obj_get_opaque(const struct lws_jrpc_obj *r)
const char * method_name
Definition: lws-jrpc.h:78
lejp_callback cb
Definition: lws-jrpc.h:80
LWS_VISIBLE LWS_EXTERN void lws_jrpc_obj_destroy(struct lws_jrpc_obj **_r)
@ LWSJRPC_PARSE_RESPONSE
Definition: lws-jrpc.h:137
@ LWSJRPC_PARSE_REQUEST
Definition: lws-jrpc.h:136
LWS_VISIBLE LWS_EXTERN void lws_jrpc_destroy(struct lws_jrpc **jrpc)
@ LWSJRPCE__NO_ERROR
Definition: lws-jrpc.h:122
@ LWSJRPCWKE__SERVER_ERROR_LAST
Definition: lws-jrpc.h:130
@ LWSJRPCE__INVALID_MEMBERS
Definition: lws-jrpc.h:132
@ LWSJRPCWKE__INVALID_REQUEST
Definition: lws-jrpc.h:125
@ LWSJRPCWKE__INVALID_PARAMS
Definition: lws-jrpc.h:127
@ LWSJRPCWKE__SERVER_ERROR_FIRST
Definition: lws-jrpc.h:129
@ LWSJRPCWKE__INTERNAL_ERROR
Definition: lws-jrpc.h:128
@ LWSJRPCWKE__METHOD_NOT_FOUND
Definition: lws-jrpc.h:126
@ LWSJRPCWKE__PARSE_ERROR
Definition: lws-jrpc.h:124
LWS_VISIBLE LWS_EXTERN int lws_jrpc_obj_parse(struct lws_jrpc *jrpc, int type, void *opaque, const char *buf, size_t l, struct lws_jrpc_obj **r)
const char *const * paths
Definition: lws-jrpc.h:79