2 * Copyright 2016 IoT.bzh
3 * Author: José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
27 #include <json-c/json.h>
37 static void wsj1_on_hangup(struct afb_wsj1 *ws);
38 static void wsj1_on_text(struct afb_wsj1 *ws, char *text, size_t size);
40 static struct afb_ws_itf wsj1_itf = {
41 .on_hangup = (void*)wsj1_on_hangup,
42 .on_text = (void*)wsj1_on_text
47 struct wsj1_call *next;
48 void (*callback)(void *, struct afb_wsj1_msg *);
56 struct afb_wsj1 *wsj1;
57 struct afb_wsj1_msg *next, *previous;
65 size_t object_s_length;
67 struct json_object *object_j;
74 struct afb_wsj1_itf *itf;
76 struct json_tokener *tokener;
78 struct afb_wsj1_msg *messages;
79 struct wsj1_call *calls;
82 struct afb_wsj1 *afb_wsj1_create(int fd, struct afb_wsj1_itf *itf, void *closure)
84 struct afb_wsj1 *result;
88 result = calloc(1, sizeof * result);
94 result->closure = closure;
96 result->tokener = json_tokener_new();
97 if (result->tokener == NULL)
100 result->ws = afb_ws_create(fd, &wsj1_itf, result);
101 if (result->ws == NULL)
107 json_tokener_free(result->tokener);
115 void afb_wsj1_addref(struct afb_wsj1 *wsj1)
121 void afb_wsj1_unref(struct afb_wsj1 *wsj1)
123 if (wsj1 != NULL && !--wsj1->refcount) {
124 afb_ws_destroy(wsj1->ws);
125 json_tokener_free(wsj1->tokener);
130 static void wsj1_on_hangup(struct afb_wsj1 *ws)
132 if (ws->itf->on_hangup != NULL)
133 ws->itf->on_hangup(ws->closure);
137 static struct wsj1_call *wsj1_call_search(struct afb_wsj1 *wsj1, const char *id, int remove)
139 struct wsj1_call *r, **p;
141 while((r = *p) != NULL) {
142 if (strcmp(r->id, id) == 0) {
152 static struct wsj1_call *wsj1_call_create(struct afb_wsj1 *wsj1, void (*on_reply)(void*,struct afb_wsj1_msg*), void *closure)
154 struct wsj1_call *call = malloc(sizeof *call);
159 if (wsj1->genid == 0)
160 wsj1->genid = 999999;
161 sprintf(call->id, "%d", wsj1->genid--);
162 } while (wsj1_call_search(wsj1, call->id, 0) != NULL);
163 call->callback = on_reply;
164 call->closure = closure;
165 call->next = wsj1->calls;
172 static int wsj1_msg_scan(char *text, size_t items[10][2])
174 char *pos, *beg, *end, c;
181 while(*pos == ' ') pos++;
182 if (*pos++ != '[') goto bad_scan;
185 while(*pos == ' ') pos++;
192 while (aux != 0 || (*pos != ',' && *pos != ']')) {
194 case '{': case '[': aux++; break;
195 case '}': case ']': if (aux--) break;
196 case 0: goto bad_scan;
200 case '\\': if (*pos++) break;
201 case 0: goto bad_scan;
207 while (end > beg && end[-1] == ' ')
209 items[n][0] = beg - text; /* start offset */
210 items[n][1] = end - beg; /* length */
214 while(*++pos == ' ');
217 while(*++pos == ' ');
218 if (*pos) goto bad_scan;
225 static char *wsj1_msg_parse_extract(char *text, size_t offset, size_t size)
227 text[offset + size] = 0;
228 return text + offset;
231 static char *wsj1_msg_parse_string(char *text, size_t offset, size_t size)
233 if (size > 1 && text[offset] == '"') {
237 return wsj1_msg_parse_extract(text, offset, size);
240 static void wsj1_on_text(struct afb_wsj1 *wsj1, char *text, size_t size)
244 struct afb_wsj1_msg *msg;
245 struct wsj1_call *call;
248 msg = calloc(1, sizeof *msg);
253 n = wsj1_msg_scan(text, items);
257 /* scans code: 2|3|4|5 */
258 if (items[0][1] != 1) goto bad_header;
259 switch (text[items[0][0]]) {
260 case '2': msg->code = CALL; break;
261 case '3': msg->code = RETOK; break;
262 case '4': msg->code = RETERR; break;
263 case '5': msg->code = EVENT; break;
264 default: goto bad_header;
267 /* fills the message */
270 if (n != 4 && n != 5) goto bad_header;
271 msg->id = wsj1_msg_parse_string(text, items[1][0], items[1][1]);
272 msg->api = wsj1_msg_parse_string(text, items[2][0], items[2][1]);
273 msg->verb = strchr(msg->api, '/');
274 if (msg->verb == NULL) goto bad_header;
276 msg->object_s = wsj1_msg_parse_extract(text, items[3][0], items[3][1]);
277 msg->object_s_length = items[3][1];
278 msg->token = n == 5 ? wsj1_msg_parse_string(text, items[4][0], items[4][1]) : NULL;
282 if (n != 3 && n != 4) goto bad_header;
283 msg->id = wsj1_msg_parse_string(text, items[1][0], items[1][1]);
284 call = wsj1_call_search(wsj1, msg->id, 1);
285 if (call == NULL) goto bad_header;
286 msg->object_s = wsj1_msg_parse_extract(text, items[2][0], items[2][1]);
287 msg->object_s_length = items[2][1];
288 msg->token = n == 5 ? wsj1_msg_parse_string(text, items[3][0], items[3][1]) : NULL;
291 if (n != 3) goto bad_header;
292 msg->event = wsj1_msg_parse_string(text, items[1][0], items[1][1]);
293 msg->object_s = wsj1_msg_parse_extract(text, items[2][0], items[2][1]);
294 msg->object_s_length = items[2][1];
300 /* fill and record the request */
302 afb_wsj1_addref(wsj1);
304 msg->next = wsj1->messages;
305 msg->next->previous = msg;
306 wsj1->messages = msg;
308 /* incoke the handler */
311 wsj1->itf->on_call(wsj1->closure, msg->api, msg->verb, msg);
315 call->callback(call->closure, msg);
319 wsj1->itf->on_event(wsj1->closure, msg->event, msg);
322 afb_wsj1_msg_unref(msg);
329 afb_ws_close(wsj1->ws, 1008, NULL);
332 void afb_wsj1_msg_addref(struct afb_wsj1_msg *msg)
338 void afb_wsj1_msg_unref(struct afb_wsj1_msg *msg)
340 if (msg != NULL && --msg->refcount == 0) {
341 /* unlink the message */
342 if (msg->next != NULL)
343 msg->next->previous = msg->previous;
344 if (msg->previous == NULL)
345 msg->wsj1->messages = msg->next;
347 msg->previous->next = msg->next;
348 /* free ressources */
349 afb_wsj1_unref(msg->wsj1);
350 json_object_put(msg->object_j);
356 const char *afb_wsj1_msg_object_s(struct afb_wsj1_msg *msg)
358 return msg->object_s;
361 struct json_object *afb_wsj1_msg_object_j(struct afb_wsj1_msg *msg)
363 struct json_object *object = msg->object_j;
364 if (object == NULL) {
365 json_tokener_reset(msg->wsj1->tokener);
366 object = json_tokener_parse_ex(msg->wsj1->tokener, msg->object_s, (int)msg->object_s_length);
367 if (object == NULL) {
368 /* lazy error detection of json request. Is it to improve? */
369 object = json_object_new_string_len(msg->object_s, (int)msg->object_s_length);
371 msg->object_j = object;
376 int afb_wsj1_msg_is_call(struct afb_wsj1_msg *msg)
378 return msg->code == CALL;
381 int afb_wsj1_msg_is_reply(struct afb_wsj1_msg *msg)
383 return msg->code == RETOK || msg->code == RETERR;
386 int afb_wsj1_msg_is_reply_ok(struct afb_wsj1_msg *msg)
388 return msg->code == RETOK;
391 int afb_wsj1_msg_is_reply_error(struct afb_wsj1_msg *msg)
393 return msg->code == RETERR;
396 int afb_wsj1_msg_is_event(struct afb_wsj1_msg *msg)
398 return msg->code == EVENT;
401 const char *afb_wsj1_msg_api(struct afb_wsj1_msg *msg)
406 const char *afb_wsj1_msg_verb(struct afb_wsj1_msg *msg)
411 const char *afb_wsj1_msg_event(struct afb_wsj1_msg *msg)
416 const char *afb_wsj1_msg_token(struct afb_wsj1_msg *msg)
436 static void wsj1_emit(struct afb_wsj1 *wsj1, int code, const char *id, size_t idlen, struct json_object *data, const char *token)
441 /* pack the message */
442 msg = json_object_new_array();
443 json_object_array_add(msg, json_object_new_int(code));
444 json_object_array_add(msg, json_object_new_string_len(id, (int)idlen));
445 json_object_array_add(msg, data);
447 json_object_array_add(msg, json_object_new_string(token));
449 /* emits the reply */
450 txt = json_object_to_json_string(msg);
451 afb_ws_text(wsj1->ws, txt, strlen(txt));
452 json_object_put(msg);
455 static void wsj1_msg_reply(struct afb_wsj1_msg *msg, int retcode, const char *status, const char *info, json_object *resp)
457 const char *token = afb_context_sent_token(&msg->context);
458 wsj1_emit(msg->wsj1, retcode, msg->id, msg->idlen, afb_msg_json_reply(status, info, resp, token, NULL), token);
461 static void wsj1_msg_fail(struct afb_wsj1_msg *msg, const char *status, const char *info)
463 wsj1_msg_reply(msg, RETERR, status, info, NULL);
466 static void wsj1_msg_success(struct afb_wsj1_msg *msg, json_object *obj, const char *info)
468 wsj1_msg_reply(msg, RETOK, "success", info, obj);
471 static const char *wsj1_msg_raw(struct afb_wsj1_msg *msg, size_t *size)
477 static void wsj1_msg_send(struct afb_wsj1_msg *msg, const char *buffer, size_t size)
479 afb_ws_text(msg->wsj1->ws, buffer, size);
482 static void wsj1_send_event(struct afb_wsj1 *wsj1, const char *event, struct json_object *object)
484 wsj1_emit(wsj1, EVENT, event, strlen(event), afb_msg_json_event(event, object), NULL);
505 static int wsj1_send_isot(struct afb_wsj1 *wsj1, int i1, const char *s1, const char *o1, const char *t1)
507 char code[2] = { (char)('0' + i1), 0 };
508 return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",", o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL);
511 static int wsj1_send_issot(struct afb_wsj1 *wsj1, int i1, const char *s1, const char *s2, const char *o1, const char *t1)
513 char code[2] = { (char)('0' + i1), 0 };
514 return afb_ws_texts(wsj1->ws, "[", code, ",\"", s1, "\",\"", s2, "\",", o1, t1 != NULL ? ",\"" : "]", t1, "\"]", NULL);
517 int afb_wsj1_send_event_j(struct afb_wsj1 *wsj1, const char *event, struct json_object *object)
519 return afb_wsj1_send_event_s(wsj1, event, json_object_to_json_string(object));
522 int afb_wsj1_send_event_s(struct afb_wsj1 *wsj1, const char *event, const char *object)
524 return wsj1_send_isot(wsj1, EVENT, event, object, NULL);
527 int afb_wsj1_call_j(struct afb_wsj1 *wsj1, const char *api, const char *verb, struct json_object *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure)
529 return afb_wsj1_call_s(wsj1, api, verb, json_object_to_json_string(object), on_reply, closure);
532 int afb_wsj1_call_s(struct afb_wsj1 *wsj1, const char *api, const char *verb, const char *object, void (*on_reply)(void *closure, struct afb_wsj1_msg *msg), void *closure)
535 struct wsj1_call *call;
538 /* allocates the call */
539 call = wsj1_call_create(wsj1, on_reply, closure);
546 tag = alloca(2 + strlen(api) + strlen(verb));
547 stpcpy(stpcpy(stpcpy(tag, api), "/"), verb);
550 rc = wsj1_send_issot(wsj1, CALL, call->id, tag, object, NULL);
552 wsj1_call_search(wsj1, call->id, 1);
559 int afb_wsj1_reply_ok_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token)
561 return afb_wsj1_reply_ok_s(msg, json_object_to_json_string(object), token);
564 int afb_wsj1_reply_ok_s(struct afb_wsj1_msg *msg, const char *object, const char *token)
566 return wsj1_send_isot(msg->wsj1, RETOK, msg->id, object, token);
569 int afb_wsj1_reply_error_j(struct afb_wsj1_msg *msg, struct json_object *object, const char *token)
571 return afb_wsj1_reply_error_s(msg, json_object_to_json_string(object), token);
574 int afb_wsj1_reply_error_s(struct afb_wsj1_msg *msg, const char *object, const char *token)
576 return wsj1_send_isot(msg->wsj1, RETERR, msg->id, object, token);