-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)
-{
- int fd;
- struct afb_websock *result;
-
- fd = MHD_get_connection_info(hreq->connection,
- MHD_CONNECTION_INFO_CONNECTION_FD)->connect_fd;
- fd = dup(fd);
- if (fd < 0)
- return NULL;
-
- result = malloc(sizeof * result);
- if (result == NULL)
- goto error;
-
- result->connection = hreq->connection;
- result->fd = 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:
- close(fd);
- 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");