Enhance client->server protocol
[src/app-framework-binder.git] / src / afb-api-ws.c
index 8be74c0..9b1d8cc 100644 (file)
@@ -53,7 +53,15 @@ struct api_ws_memo;
 struct api_ws_event;
 struct api_ws_client;
 
-
+#define CHAR_FOR_CALL             'C'
+#define CHAR_FOR_ANSWER_SUCCESS   'T'
+#define CHAR_FOR_ANSWER_FAIL      'F'
+#define CHAR_FOR_EVT_BROADCAST    '*'
+#define CHAR_FOR_EVT_ADD          '+'
+#define CHAR_FOR_EVT_DEL          '-'
+#define CHAR_FOR_EVT_PUSH         '!'
+#define CHAR_FOR_EVT_SUBSCRIBE    'S'
+#define CHAR_FOR_EVT_UNSUBSCRIBE  'U'
 
 /*
  */
@@ -153,17 +161,16 @@ static const struct afb_ws_itf api_ws_server_ws_itf =
 struct api_ws_server_req {
        struct afb_xreq xreq;           /* the xreq */
        struct api_ws_client *client;   /* the client of the request */
-       char *rcvdata;                  /* the received data to free */
        const char *request;            /* the readen request as string */
        size_t lenreq;                  /* the length of the request */
        uint32_t msgid;                 /* the incoming request msgid */
 };
 
-static void api_ws_server_req_success_cb(void *closure, struct json_object *obj, const char *info);
-static void api_ws_server_req_fail_cb(void *closure, const char *status, const char *info);
-static void api_ws_server_req_destroy_cb(void *closure);
-static int api_ws_server_req_subscribe_cb(void *closure, struct afb_event event);
-static int api_ws_server_req_unsubscribe_cb(void *closure, struct afb_event event);
+static void api_ws_server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info);
+static void api_ws_server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info);
+static void api_ws_server_req_destroy_cb(struct afb_xreq *xreq);
+static int api_ws_server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event event);
+static int api_ws_server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event event);
 
 const struct afb_xreq_query_itf afb_api_ws_xreq_itf = {
        .success = api_ws_server_req_success_cb,
@@ -737,28 +744,28 @@ static void api_ws_client_on_binary(void *closure, char *data, size_t size)
        if (size > 0) {
                struct readbuf rb = { .head = data, .end = data + size };
                switch (*rb.head++) {
-               case 'T': /* success */
+               case CHAR_FOR_ANSWER_SUCCESS: /* success */
                        api_ws_client_reply_success(closure, &rb);
                        break;
-               case 'F': /* fail */
+               case CHAR_FOR_ANSWER_FAIL: /* fail */
                        api_ws_client_reply_fail(closure, &rb);
                        break;
-               case '*': /* broadcast */
+               case CHAR_FOR_EVT_BROADCAST: /* broadcast */
                        api_ws_client_event_broadcast(closure, &rb);
                        break;
-               case '+': /* creates the event */
+               case CHAR_FOR_EVT_ADD: /* creates the event */
                        api_ws_client_event_create(closure, &rb);
                        break;
-               case '-': /* drops the event */
+               case CHAR_FOR_EVT_DEL: /* drops the event */
                        api_ws_client_event_drop(closure, &rb);
                        break;
-               case '!': /* pushs the event */
+               case CHAR_FOR_EVT_PUSH: /* pushs the event */
                        api_ws_client_event_push(closure, &rb);
                        break;
-               case 'S': /* subscribe event for a request */
+               case CHAR_FOR_EVT_SUBSCRIBE: /* subscribe event for a request */
                        api_ws_client_event_subscribe(closure, &rb);
                        break;
-               case 'U': /* unsubscribe event for a request */
+               case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */
                        api_ws_client_event_unsubscribe(closure, &rb);
                        break;
                default: /* unexpected message */
@@ -789,7 +796,8 @@ static void api_ws_client_call_cb(void * closure, struct afb_xreq *xreq)
        raw = afb_xreq_raw(xreq, &szraw);
        if (raw == NULL)
                goto internal_error;
-       if (!api_ws_write_uint32(&wb, memo->msgid)
+       if (!api_ws_write_char(&wb, CHAR_FOR_CALL)
+        || !api_ws_write_uint32(&wb, memo->msgid)
         || !api_ws_write_uint32(&wb, (uint32_t)xreq->context.flags)
         || !api_ws_write_string(&wb, xreq->verb)
         || !api_ws_write_string(&wb, afb_session_uuid(xreq->context.session))
@@ -913,7 +921,7 @@ static void api_ws_server_client_unref(struct api_ws_client *client)
 }
 
 /* on call, propagate it to the ws service */
-static void api_ws_server_called(struct api_ws_client *client, struct readbuf *rb, char *data, size_t size)
+static void api_ws_server_on_call(struct api_ws_client *client, struct readbuf *rb)
 {
        struct api_ws_server_req *wreq;
        const char *uuid, *verb;
@@ -927,7 +935,6 @@ static void api_ws_server_called(struct api_ws_client *client, struct readbuf *r
                goto out_of_memory;
 
        wreq->client = client;
-       wreq->rcvdata = data;
 
        /* reads the call message data */
        if (!api_ws_read_uint32(rb, &wreq->msgid)
@@ -937,6 +944,7 @@ static void api_ws_server_called(struct api_ws_client *client, struct readbuf *r
         || !api_ws_read_string(rb, &wreq->request, &wreq->lenreq))
                goto overflow;
 
+       afb_xreq_init(&wreq->xreq, &afb_api_ws_xreq_itf);
        wreq->xreq.json = json_tokener_parse(wreq->request);
        if (wreq->xreq.json == NULL && strcmp(wreq->request, "null")) {
                wreq->xreq.json = json_object_new_string(wreq->request);
@@ -948,11 +956,9 @@ static void api_ws_server_called(struct api_ws_client *client, struct readbuf *r
        wreq->xreq.context.flags = flags;
 
        /* makes the call */
-       wreq->xreq.refcount = 1;
+       wreq->xreq.cred = afb_cred_addref(client->cred);
        wreq->xreq.api = client->api;
        wreq->xreq.verb = verb;
-       wreq->xreq.query = wreq;
-       wreq->xreq.queryitf = &afb_api_ws_xreq_itf;
        afb_apis_call(&wreq->xreq);
        afb_xreq_unref(&wreq->xreq);
        return;
@@ -960,15 +966,24 @@ static void api_ws_server_called(struct api_ws_client *client, struct readbuf *r
 out_of_memory:
 overflow:
        free(wreq);
-       free(data);
        api_ws_server_client_unref(client);
 }
 
 /* callback when receiving binary data */
 static void api_ws_server_on_binary(void *closure, char *data, size_t size)
 {
-       struct readbuf rb = { .head = data, .end = data + size };
-       api_ws_server_called(closure, &rb, data, size);
+       if (size > 0) {
+               struct readbuf rb = { .head = data, .end = data + size };
+               switch (*rb.head++) {
+               case CHAR_FOR_CALL:
+                       api_ws_server_on_call(closure, &rb);
+                       break;
+               default: /* unexpected message */
+                       /* TODO: close the connection */
+                       break;
+               }
+       }
+       free(data);
 }
 
 /* callback when receiving a hangup */
@@ -1037,18 +1052,18 @@ static void api_ws_server_event_send(struct api_ws_client *client, char order, c
 
 static void api_ws_server_event_add(void *closure, const char *event, int eventid)
 {
-       api_ws_server_event_send(closure, '+', event, eventid, NULL);
+       api_ws_server_event_send(closure, CHAR_FOR_EVT_ADD, event, eventid, NULL);
 }
 
 static void api_ws_server_event_remove(void *closure, const char *event, int eventid)
 {
-       api_ws_server_event_send(closure, '-', event, eventid, NULL);
+       api_ws_server_event_send(closure, CHAR_FOR_EVT_DEL, event, eventid, NULL);
 }
 
 static void api_ws_server_event_push(void *closure, const char *event, int eventid, struct json_object *object)
 {
        const char *data = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN);
-       api_ws_server_event_send(closure, '!', event, eventid, data ? : "null");
+       api_ws_server_event_send(closure, CHAR_FOR_EVT_PUSH, event, eventid, data ? : "null");
        json_object_put(object);
 }
 
@@ -1059,7 +1074,7 @@ static void api_ws_server_event_broadcast(void *closure, const char *event, int
 
        struct writebuf wb = { .count = 0 };
 
-       if (api_ws_write_char(&wb, '*') && api_ws_write_string(&wb, event) && api_ws_write_object(&wb, object)) {
+       if (api_ws_write_char(&wb, CHAR_FOR_EVT_BROADCAST) && api_ws_write_string(&wb, event) && api_ws_write_object(&wb, object)) {
                rc = afb_ws_binary_v(client->ws, wb.iovec, wb.count);
                if (rc < 0)
                        ERROR("error while broadcasting event %s", event);
@@ -1071,24 +1086,24 @@ static void api_ws_server_event_broadcast(void *closure, const char *event, int
 /******************* ws request part for server *****************/
 
 /* decrement the reference count of the request and free/release it on falling to null */
-static void api_ws_server_req_destroy_cb(void *closure)
+static void api_ws_server_req_destroy_cb(struct afb_xreq *xreq)
 {
-       struct api_ws_server_req *wreq = closure;
+       struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
 
        afb_context_disconnect(&wreq->xreq.context);
+       afb_cred_unref(wreq->xreq.cred);
        json_object_put(wreq->xreq.json);
-       free(wreq->rcvdata);
        api_ws_server_client_unref(wreq->client);
        free(wreq);
 }
 
-static void api_ws_server_req_success_cb(void *closure, struct json_object *obj, const char *info)
+static void api_ws_server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info)
 {
        int rc;
        struct writebuf wb = { .count = 0 };
-       struct api_ws_server_req *wreq = closure;
+       struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
 
-       if (api_ws_write_char(&wb, 'T')
+       if (api_ws_write_char(&wb, CHAR_FOR_ANSWER_SUCCESS)
         && api_ws_write_uint32(&wb, wreq->msgid)
         && api_ws_write_uint32(&wb, (uint32_t)wreq->xreq.context.flags)
         && api_ws_write_string(&wb, info ? : "")
@@ -1102,13 +1117,13 @@ success:
        json_object_put(obj);
 }
 
-static void api_ws_server_req_fail_cb(void *closure, const char *status, const char *info)
+static void api_ws_server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info)
 {
        int rc;
        struct writebuf wb = { .count = 0 };
-       struct api_ws_server_req *wreq = closure;
+       struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
 
-       if (api_ws_write_char(&wb, 'F')
+       if (api_ws_write_char(&wb, CHAR_FOR_ANSWER_FAIL)
         && api_ws_write_uint32(&wb, wreq->msgid)
         && api_ws_write_uint32(&wb, (uint32_t)wreq->xreq.context.flags)
         && api_ws_write_string(&wb, status)
@@ -1120,17 +1135,17 @@ static void api_ws_server_req_fail_cb(void *closure, const char *status, const c
        ERROR("error while sending fail");
 }
 
-static int api_ws_server_req_subscribe_cb(void *closure, struct afb_event event)
+static int api_ws_server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event event)
 {
        int rc, rc2;
        struct writebuf wb = { .count = 0 };
-       struct api_ws_server_req *wreq = closure;
+       struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
 
        rc = afb_evt_add_watch(wreq->client->listener, event);
        if (rc < 0)
                return rc;
 
-       if (api_ws_write_char(&wb, 'S')
+       if (api_ws_write_char(&wb, CHAR_FOR_EVT_SUBSCRIBE)
         && api_ws_write_uint32(&wb, wreq->msgid)
         && api_ws_write_uint32(&wb, (uint32_t)afb_evt_event_id(event))
         && api_ws_write_string(&wb, afb_evt_event_name(event))) {
@@ -1143,13 +1158,13 @@ success:
        return rc;
 }
 
-static int api_ws_server_req_unsubscribe_cb(void *closure, struct afb_event event)
+static int api_ws_server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event event)
 {
        int rc, rc2;
        struct writebuf wb = { .count = 0 };
-       struct api_ws_server_req *wreq = closure;
+       struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
 
-       if (api_ws_write_char(&wb, 'U')
+       if (api_ws_write_char(&wb, CHAR_FOR_EVT_UNSUBSCRIBE)
         && api_ws_write_uint32(&wb, wreq->msgid)
         && api_ws_write_uint32(&wb, (uint32_t)afb_evt_event_id(event))
         && api_ws_write_string(&wb, afb_evt_event_name(event))) {