-struct afb_wsreq
-{
- struct afb_websock *aws;
- struct afb_wsreq *next;
- struct json_object *id;
- struct json_object *name;
- struct json_object *token;
- struct json_object *request;
-};
-
-struct afb_websock
-{
- int fd;
- struct MHD_Connection *connection;
- struct websock *ws;
- struct upoll *up;
- struct AFB_clientCtx *context;
- struct json_tokener *tokener;
- struct afb_wsreq *requests;
-};
-
-static struct afb_arg wsreq_get(struct afb_wsreq *wsreq, const char *name);
-static void wsreq_iterate(struct afb_wsreq *wsreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure);
-static void wsreq_fail(struct afb_wsreq *wsreq, const char *status, const char *info);
-static void wsreq_success(struct afb_wsreq *wsreq, struct json_object *obj, const char *info);
-static int wsreq_session_create(struct afb_wsreq *wsreq);
-static int wsreq_session_check(struct afb_wsreq *wsreq, int refresh);
-static void wsreq_session_close(struct afb_wsreq *wsreq);
-
-static const struct afb_req_itf wsreq_itf = {
- .get = (void*)wsreq_get,
- .iterate = (void*)wsreq_iterate,
- .fail = (void*)wsreq_fail,
- .success = (void*)wsreq_success,
- .session_create = (void*)wsreq_session_create,
- .session_check = (void*)wsreq_session_check,
- .session_close = (void*)wsreq_session_close
-};
-
-struct afb_websock *afb_websock_create(struct afb_hreq *hreq)
-{
- struct afb_websock *result;
-
- result = malloc(sizeof * result);
- if (result == NULL)
- goto error;
-
- result->connection = hreq->connection;
- result->fd = MHD_get_connection_info(hreq->connection,
- MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
- result->context = ctxClientGet(afb_hreq_context(hreq));
- if (result->context == NULL)
- goto error2;
-
- result->tokener = json_tokener_new();
- if (result->tokener == NULL)
- goto error2;
-
- result->ws = websock_create(&aws_itf, result);
- if (result->ws == NULL)
- goto error3;
-
- result->up = upoll_open(result->fd, result);
- if (result->up == NULL)
- goto error4;
-
- upoll_on_readable(result->up, (void*)aws_on_readable);
- upoll_on_hangup(result->up, (void*)aws_disconnect);
- return result;
-error4:
- websock_destroy(result->ws);
-error3:
- json_tokener_free(result->tokener);
-error2:
- free(result);
-error:
- return NULL;
-}
-
-static ssize_t aws_writev(struct afb_websock *ws, const struct iovec *iov, int iovcnt)
-{
- ssize_t rc;
- do {
- rc = writev(ws->fd, iov, iovcnt);
- } while(rc == -1 && errno == EINTR);
- return rc;
-}
-
-static ssize_t aws_readv(struct afb_websock *ws, const struct iovec *iov, int iovcnt)
-{
- ssize_t rc;
- do {
- rc = readv(ws->fd, iov, iovcnt);
- } while(rc == -1 && errno == EINTR);
- return rc;
-}
-
-static void aws_disconnect(struct afb_websock *ws)
-{
- upoll_close(ws->up);
- websock_destroy(ws->ws);
- close(ws->fd);
- MHD_resume_connection (ws->connection);
- ctxClientPut(ws->context);
- json_tokener_free(ws->tokener);
- free(ws);
-}
-
-static void aws_on_close(struct afb_websock *ws, uint16_t code, size_t size)
-{
- /* do nothing */
-}
-
-static void aws_on_readable(struct afb_websock *ws)
-{
- websock_dispatch(ws->ws);
-}
-
-static int aws_handle_json(struct afb_websock *aws, struct json_object *obj)
-{
- struct afb_req r;
- int count, num, rc;
- struct json_object *type, *id, *name, *req, *token;
- struct afb_wsreq *wsreq;
- const char *api, *verb;
- size_t lenapi, lenverb;
-
- /* protocol inspired by http://www.gir.fr/ocppjs/ocpp_srpc_spec.shtml */
-
- /* the object must be an array of 4 or 5 elements */
- if (!json_object_is_type(obj, json_type_array))
- goto error;
- count = json_object_array_length(obj);
- if (count < 4 || count > 5)
- goto error;
-
- /* get the 5 elements: type id name request token */
- type = json_object_array_get_idx(obj, 0);
- id = json_object_array_get_idx(obj, 1);
- name = json_object_array_get_idx(obj, 2);
- req = json_object_array_get_idx(obj, 3);
- token = json_object_array_get_idx(obj, 4);
-
- /* check the types: int string string object string */
- if (!json_object_is_type(type, json_type_int))
- goto error;
- if (!json_object_is_type(id, json_type_string))
- goto error;
- if (!json_object_is_type(name, json_type_string))
- goto error;
- if (!json_object_is_type(req, json_type_object))
- goto error;
- if (token != NULL && !json_object_is_type(token, json_type_string))
- goto error;
-
- /* the type is only 2 */
- num = json_object_get_int(type);
- if (num != 2)
- goto error;
-
- /* checks the api/verb structure of name */
- api = json_object_get_string(name);
- for (lenapi = 0 ; api[lenapi] && api[lenapi] != '/' ; lenapi++);
- if (!lenapi || !api[lenapi])
- goto error;
- verb = &api[lenapi+1];
- for (lenverb = 0 ; verb[lenverb] && verb[lenverb] != '/' ; lenverb++);
- if (!lenverb || !verb[lenverb])
- goto error;
-
- /* allocates the request data */
- wsreq = malloc(sizeof *wsreq);
- if (wsreq == NULL)
- goto error;
-
- /* fill and record the request */
- wsreq->aws = aws;
- wsreq->id = json_object_get(id);
- wsreq->name = json_object_get(name);
- wsreq->token = json_object_get(token);
- wsreq->request = json_object_get(req);
- wsreq->next = aws->requests;
- aws->requests = wsreq;
- json_object_put(obj);
-
- r.data = wsreq;
- r.itf = &wsreq_itf;
- rc = afb_apis_handle(r, aws->context, api, lenapi, verb, lenverb);
- if (rc == 0)
- wsreq_fail(wsreq, "ail", "api not found");
- return 1;
-
-error:
- json_object_put(obj);
- return 0;
-}
-
-static void aws_on_content(struct afb_websock *ws, int last, size_t size)
-{
- ssize_t rrc;
- char buffer[8000];
- struct json_object *obj;
-
- json_tokener_reset(ws->tokener);
- while(size) {
- rrc = websock_read(ws->ws, buffer,
- size > sizeof buffer ? sizeof buffer : size);
- if (rrc < 0) {
- websock_close(ws->ws);
- return;
- }
- size -= (size_t)rrc;
- obj = json_tokener_parse_ex(ws->tokener, buffer, (int)rrc);
- if (obj != NULL) {
- if (!aws_handle_json(ws, obj)) {
- websock_close(ws->ws);
- return;
- }
- } else if (json_tokener_get_error(ws->tokener) != json_tokener_continue) {
- websock_close(ws->ws);
- return;
- }
- }
-}
-
-
-static struct afb_arg wsreq_get(struct afb_wsreq *wsreq, const char *name)
-{
- struct afb_arg arg;
- struct json_object *value;
-
- if (json_object_object_get_ex(wsreq->request, name, &value)) {
- arg.name = name;
- arg.value = json_object_get_string(value);
- } else {
- arg.name = NULL;
- arg.value = NULL;
- }
- arg.size = 0;
- arg.is_file = 0;
- return arg;
-}
-
-static void wsreq_iterate(struct afb_wsreq *wsreq, int (*iterator)(void *closure, struct afb_arg arg), void *closure)
-{
- struct afb_arg arg;
- struct json_object_iterator it = json_object_iter_begin(wsreq->request);
- struct json_object_iterator end = json_object_iter_end(wsreq->request);
-
- arg.size = 0;
- arg.is_file = 0;
- while(!json_object_iter_equal(&it, &end)) {
- arg.name = json_object_iter_peek_name(&it);
- arg.value = json_object_get_string(json_object_iter_peek_value(&it));
- if (!iterator(closure, arg))
- break;
- json_object_iter_next(&it);
- }
-}
-
-static int wsreq_session_create(struct afb_wsreq *wsreq)