Improve interface xreq
[src/app-framework-binder.git] / src / afb-api-ws.c
index 663170e..89b83bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
  * Author José Bollo <jose.bollo@iot.bzh>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +37,7 @@
 
 #include "afb-common.h"
 
-#include "session.h"
+#include "afb-session.h"
 #include "afb-ws.h"
 #include "afb-msg-json.h"
 #include "afb-apis.h"
@@ -46,6 +46,7 @@
 #include "afb-evt.h"
 #include "afb-subcall.h"
 #include "verbose.h"
+#include "sd-fds.h"
 
 struct api_ws_memo;
 struct api_ws_event;
@@ -157,33 +158,36 @@ struct api_ws_server_req {
 };
 
 static struct json_object *api_ws_server_req_json(struct api_ws_server_req *wreq);
-static struct afb_arg api_ws_server_req_get(struct api_ws_server_req *wreq, const char *name);
-static void api_ws_server_req_success(struct api_ws_server_req *wreq, struct json_object *obj, const char *info);
-static void api_ws_server_req_fail(struct api_ws_server_req *wreq, const char *status, const char *info);
-static const char *api_ws_server_req_raw(struct api_ws_server_req *wreq, size_t *size);
-static void api_ws_server_req_send(struct api_ws_server_req *wreq, const char *buffer, size_t size);
-static void api_ws_server_req_addref(struct api_ws_server_req *wreq);
 static void api_ws_server_req_unref(struct api_ws_server_req *wreq);
-static int api_ws_server_req_subscribe(struct api_ws_server_req *wreq, struct afb_event event);
-static int api_ws_server_req_unsubscribe(struct api_ws_server_req *wreq, struct afb_event event);
-static void api_ws_server_req_subcall(struct api_ws_server_req *wreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure);
+
+static struct json_object *api_ws_server_req_json_cb(void *closure);
+static struct afb_arg api_ws_server_req_get_cb(void *closure, const char *name);
+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 const char *api_ws_server_req_raw_cb(void *closure, size_t *size);
+static void api_ws_server_req_send_cb(void *closure, const char *buffer, size_t size);
+static void api_ws_server_req_addref_cb(void *closure);
+static void api_ws_server_req_unref_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_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure);
 
 const struct afb_req_itf afb_api_ws_req_itf = {
-       .json = (void*)api_ws_server_req_json,
-       .get = (void*)api_ws_server_req_get,
-       .success = (void*)api_ws_server_req_success,
-       .fail = (void*)api_ws_server_req_fail,
-       .raw = (void*)api_ws_server_req_raw,
-       .send = (void*)api_ws_server_req_send,
+       .json = api_ws_server_req_json_cb,
+       .get = api_ws_server_req_get_cb,
+       .success = api_ws_server_req_success_cb,
+       .fail = api_ws_server_req_fail_cb,
+       .raw = api_ws_server_req_raw_cb,
+       .send = api_ws_server_req_send_cb,
        .context_get = (void*)afb_context_get,
        .context_set = (void*)afb_context_set,
-       .addref = (void*)api_ws_server_req_addref,
-       .unref = (void*)api_ws_server_req_unref,
+       .addref = api_ws_server_req_addref_cb,
+       .unref = api_ws_server_req_unref_cb,
        .session_close = (void*)afb_context_close,
        .session_set_LOA = (void*)afb_context_change_loa,
-       .subscribe = (void*)api_ws_server_req_subscribe,
-       .unsubscribe = (void*)api_ws_server_req_unsubscribe,
-       .subcall = (void*)api_ws_server_req_subcall
+       .subscribe = api_ws_server_req_subscribe_cb,
+       .unsubscribe = api_ws_server_req_unsubscribe_cb,
+       .subcall = api_ws_server_req_subcall_cb
 };
 
 /******************* common part **********************************/
@@ -205,11 +209,13 @@ static struct api_ws *api_ws_make(const char *path)
        }
 
        /* path is copied after the struct */
-       api->path = (void*)(api+1);
+       api->path = (char*)(api+1);
        memcpy(api->path, path, length + 1);
 
        /* api name is at the end of the path */
-       api->api = strrchr(api->path, '/');
+       while (length && path[length - 1] != '/' && path[length - 1] != ':')
+               length = length - 1;
+       api->api = &api->path[length];
        if (api->api == NULL || !afb_apis_is_valid_api_name(++api->api)) {
                errno = EINVAL;
                goto error2;
@@ -281,7 +287,7 @@ static int api_ws_socket_inet(const char *path, int server)
        rc = getaddrinfo(host, service, &hint, &rai);
        if (rc != 0) {
                errno = EINVAL;
-               return NULL;
+               return -1;
        }
 
        /* get the socket */
@@ -311,21 +317,29 @@ static int api_ws_socket(const char *path, int server)
 {
        int fd, rc;
 
-       /* check for unix socket */
-       if (0 == strncmp(path, "unix:", 5))
-               fd = api_ws_socket_unix(path + 5, server);
-       else
-               fd = api_ws_socket_inet(path, server);
-
-       if (fd >= 0) {
-               fcntl(fd, F_SETFD, FD_CLOEXEC);
-               fcntl(fd, F_SETFL, O_NONBLOCK);
-               if (server) {
+       /* check for systemd socket */
+       if (0 == strncmp(path, "sd:", 3))
+               fd = sd_fds_for(path + 3);
+       else {
+               /* check for unix socket */
+               if (0 == strncmp(path, "unix:", 5))
+                       /* unix socket */
+                       fd = api_ws_socket_unix(path + 5, server);
+               else
+                       /* inet socket */
+                       fd = api_ws_socket_inet(path, server);
+
+               if (fd >= 0 && server) {
                        rc = 1;
                        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof rc);
                        rc = listen(fd, 5);
                }
        }
+       /* configure the socket */
+       if (fd >= 0) {
+               fcntl(fd, F_SETFD, FD_CLOEXEC);
+               fcntl(fd, F_SETFL, O_NONBLOCK);
+       }
        return fd;
 }
 
@@ -417,12 +431,6 @@ static int api_ws_write_uint32(struct writebuf *wb, uint32_t value)
        return 1;
 }
 
-static int api_ws_write_string_nz(struct writebuf *wb, const char *value, size_t length)
-{
-       uint32_t len = (uint32_t)length;
-       return (size_t)len == length && ++len && api_ws_write_uint32(wb, len) && api_ws_write_put(wb, value, length) && api_ws_write_char(wb, '\0');
-}
-
 static int api_ws_write_string_length(struct writebuf *wb, const char *value, size_t length)
 {
        uint32_t len = (uint32_t)++length;
@@ -797,16 +805,18 @@ static void api_ws_client_on_binary(void *closure, char *data, size_t size)
                        break;
                }
        }
+       free(data);
 }
 
 /* on call, propagate it to the ws service */
-static void api_ws_client_call(struct api_ws *api, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb)
+static void api_ws_client_call_cb(void * closure, struct afb_req req, struct afb_context *context, const char *verb)
 {
        int rc;
        struct api_ws_memo *memo;
        struct writebuf wb = { .count = 0 };
        const char *raw;
        size_t szraw;
+       struct api_ws *api = closure;
 
        /* create the recording data */
        memo = api_ws_client_memo_make(api, req, context);
@@ -821,8 +831,8 @@ static void api_ws_client_call(struct api_ws *api, struct afb_req req, struct af
                goto internal_error;
        if (!api_ws_write_uint32(&wb, memo->msgid)
         || !api_ws_write_uint32(&wb, (uint32_t)context->flags)
-        || !api_ws_write_string_nz(&wb, verb, lenverb)
-        || !api_ws_write_string(&wb, ctxClientGetUuid(context->session))
+        || !api_ws_write_string(&wb, verb)
+        || !api_ws_write_string(&wb, afb_session_uuid(context->session))
         || !api_ws_write_string_length(&wb, raw, szraw))
                goto overflow;
 
@@ -847,8 +857,10 @@ clean_memo:
        api_ws_client_memo_destroy(memo);
 }
 
-static int api_ws_service_start(struct api_ws *api, int share_session, int onneed)
+static int api_ws_service_start_cb(void *closure, int share_session, int onneed)
 {
+       struct api_ws *api = closure;
+
        /* not an error when onneed */
        if (onneed != 0)
                return 0;
@@ -909,8 +921,8 @@ int afb_api_ws_add_client(const char *path)
 
        /* record it as an API */
        afb_api.closure = api;
-       afb_api.call = (void*)api_ws_client_call;
-       afb_api.service_start = (void*)api_ws_service_start;
+       afb_api.call = api_ws_client_call_cb;
+       afb_api.service_start = api_ws_service_start_cb;
        if (afb_apis_add(api->api, afb_api) < 0)
                goto error3;
 
@@ -970,7 +982,7 @@ static void api_ws_server_called(struct api_ws_client *client, struct readbuf *r
        /* makes the call */
        areq.itf = &afb_api_ws_req_itf;
        areq.closure = wreq;
-       afb_apis_call_(areq, &wreq->context, client->api, verb);
+       afb_apis_call(areq, &wreq->context, client->api, verb);
        api_ws_server_req_unref(wreq);
        return;
 
@@ -1016,6 +1028,8 @@ static void api_ws_server_accept(struct api_ws *api)
                        lenaddr = (socklen_t)sizeof addr;
                        client->fd = accept(api->fd, &addr, &lenaddr);
                        if (client->fd >= 0) {
+                               fcntl(client->fd, F_SETFD, FD_CLOEXEC);
+                               fcntl(client->fd, F_SETFL, O_NONBLOCK);
                                client->ws = afb_ws_create(afb_common_get_event_loop(), client->fd, &api_ws_server_ws_itf, client);
                                if (client->ws != NULL) {
                                        client->api = api->api;
@@ -1084,12 +1098,18 @@ static void api_ws_server_event_broadcast(void *closure, const char *event, int
 /******************* ws request part for server *****************/
 
 /* increment the reference count of the request */
-static void api_ws_server_req_addref(struct api_ws_server_req *wreq)
+static void api_ws_server_req_addref_cb(void *closure)
 {
+       struct api_ws_server_req *wreq = closure;
        wreq->refcount++;
 }
 
 /* decrement the reference count of the request and free/release it on falling to null */
+static void api_ws_server_req_unref_cb(void *closure)
+{
+       api_ws_server_req_unref(closure);
+}
+
 static void api_ws_server_req_unref(struct api_ws_server_req *wreq)
 {
        if (wreq == NULL || --wreq->refcount)
@@ -1103,6 +1123,11 @@ static void api_ws_server_req_unref(struct api_ws_server_req *wreq)
 }
 
 /* get the object of the request */
+static struct json_object *api_ws_server_req_json_cb(void *closure)
+{
+       return api_ws_server_req_json(closure);
+}
+
 static struct json_object *api_ws_server_req_json(struct api_ws_server_req *wreq)
 {
        if (wreq->json == NULL) {
@@ -1116,15 +1141,17 @@ static struct json_object *api_ws_server_req_json(struct api_ws_server_req *wreq
 }
 
 /* get the argument of the request of 'name' */
-static struct afb_arg api_ws_server_req_get(struct api_ws_server_req *wreq, const char *name)
+static struct afb_arg api_ws_server_req_get_cb(void *closure, const char *name)
 {
+       struct api_ws_server_req *wreq = closure;
        return afb_msg_json_get_arg(api_ws_server_req_json(wreq), name);
 }
 
-static void api_ws_server_req_success(struct api_ws_server_req *wreq, struct json_object *obj, const char *info)
+static void api_ws_server_req_success_cb(void *closure, struct json_object *obj, const char *info)
 {
        int rc;
        struct writebuf wb = { .count = 0 };
+       struct api_ws_server_req *wreq = closure;
 
        if (api_ws_write_char(&wb, 'T')
         && api_ws_write_uint32(&wb, wreq->msgid)
@@ -1140,10 +1167,11 @@ success:
        json_object_put(obj);
 }
 
-static void api_ws_server_req_fail(struct api_ws_server_req *wreq, const char *status, const char *info)
+static void api_ws_server_req_fail_cb(void *closure, const char *status, const char *info)
 {
        int rc;
        struct writebuf wb = { .count = 0 };
+       struct api_ws_server_req *wreq = closure;
 
        if (api_ws_write_char(&wb, 'F')
         && api_ws_write_uint32(&wb, wreq->msgid)
@@ -1157,18 +1185,20 @@ static void api_ws_server_req_fail(struct api_ws_server_req *wreq, const char *s
        ERROR("error while sending fail");
 }
 
-static const char *api_ws_server_req_raw(struct api_ws_server_req *wreq, size_t *size)
+static const char *api_ws_server_req_raw_cb(void *closure, size_t *size)
 {
+       struct api_ws_server_req *wreq = closure;
        if (size != NULL)
                *size = wreq->lenreq;
        return wreq->request;
 }
 
-static void api_ws_server_req_send(struct api_ws_server_req *wreq, const char *buffer, size_t size)
+static void api_ws_server_req_send_cb(void *closure, const char *buffer, size_t size)
 {
        /* TODO: how to put sized buffer as strings? things aren't clear here!!! */
        int rc;
        struct writebuf wb = { .count = 0 };
+       struct api_ws_server_req *wreq = closure;
 
        if (api_ws_write_char(&wb, 'X')
         && api_ws_write_uint32(&wb, wreq->msgid)
@@ -1181,10 +1211,11 @@ static void api_ws_server_req_send(struct api_ws_server_req *wreq, const char *b
        ERROR("error while sending raw");
 }
 
-static int api_ws_server_req_subscribe(struct api_ws_server_req *wreq, struct afb_event event)
+static int api_ws_server_req_subscribe_cb(void *closure, struct afb_event event)
 {
        int rc, rc2;
        struct writebuf wb = { .count = 0 };
+       struct api_ws_server_req *wreq = closure;
 
        rc = afb_evt_add_watch(wreq->client->listener, event);
        if (rc < 0)
@@ -1203,10 +1234,11 @@ success:
        return rc;
 }
 
-static int api_ws_server_req_unsubscribe(struct api_ws_server_req *wreq, struct afb_event event)
+static int api_ws_server_req_unsubscribe_cb(void *closure, struct afb_event event)
 {
        int rc, rc2;
        struct writebuf wb = { .count = 0 };
+       struct api_ws_server_req *wreq = closure;
 
        if (api_ws_write_char(&wb, 'U')
         && api_ws_write_uint32(&wb, wreq->msgid)
@@ -1222,9 +1254,10 @@ success:
        return rc;
 }
 
-static void api_ws_server_req_subcall(struct api_ws_server_req *wreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure)
+static void api_ws_server_req_subcall_cb(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
 {
-       afb_subcall(&wreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_api_ws_req_itf, .closure = wreq });
+       struct api_ws_server_req *wreq = closure;
+       afb_subcall(&wreq->context, api, verb, args, callback, cb_closure, (struct afb_req){ .itf = &afb_api_ws_req_itf, .closure = wreq });
 }
 
 /******************* server part **********************************/