Introduce apiset for grouping apis
[src/app-framework-binder.git] / src / afb-api-ws.c
1 /*
2  * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19 #define NO_PLUGIN_VERBOSE_MACRO
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <endian.h>
28 #include <netdb.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <pthread.h>
33
34 #include <json-c/json.h>
35 #include <systemd/sd-event.h>
36
37 #include <afb/afb-req-itf.h>
38
39 #include "afb-common.h"
40
41 #include "afb-session.h"
42 #include "afb-cred.h"
43 #include "afb-ws.h"
44 #include "afb-msg-json.h"
45 #include "afb-api.h"
46 #include "afb-apiset.h"
47 #include "afb-api-so.h"
48 #include "afb-context.h"
49 #include "afb-evt.h"
50 #include "afb-xreq.h"
51 #include "verbose.h"
52 #include "sd-fds.h"
53
54 struct api_ws_memo;
55 struct api_ws_event;
56 struct api_ws_client;
57
58 #define CHAR_FOR_CALL             'C'
59 #define CHAR_FOR_ANSWER_SUCCESS   'T'
60 #define CHAR_FOR_ANSWER_FAIL      'F'
61 #define CHAR_FOR_EVT_BROADCAST    '*'
62 #define CHAR_FOR_EVT_ADD          '+'
63 #define CHAR_FOR_EVT_DEL          '-'
64 #define CHAR_FOR_EVT_PUSH         '!'
65 #define CHAR_FOR_EVT_SUBSCRIBE    'S'
66 #define CHAR_FOR_EVT_UNSUBSCRIBE  'U'
67 #define CHAR_FOR_SUBCALL_CALL     'B'
68 #define CHAR_FOR_SUBCALL_REPLY    'R'
69
70 /*
71  */
72 struct api_ws
73 {
74         char *path;             /* path of the object for the API */
75         char *api;              /* api name of the interface */
76         int fd;                 /* file descriptor */
77         pthread_mutex_t mutex;  /**< resource control */
78         union {
79                 struct {
80                         uint32_t id;
81                         struct afb_ws *ws;
82                         struct api_ws_event *events;
83                         struct api_ws_memo *memos;
84                 } client;
85                 struct {
86                         sd_event_source *listensrc; /**< systemd source for server socket */
87                         struct afb_apiset *apiset;
88                 } server;
89         };
90 };
91
92 #define RETOK   1
93 #define RETERR  2
94 #define RETRAW  3
95
96 /******************* websocket interface for client part **********************************/
97
98 static void api_ws_client_on_binary(void *closure, char *data, size_t size);
99
100 static const struct afb_ws_itf api_ws_client_ws_itf =
101 {
102         .on_close = NULL,
103         .on_text = NULL,
104         .on_binary = api_ws_client_on_binary,
105         .on_error = NULL,
106         .on_hangup = NULL
107 };
108
109 /******************* event structures for server part **********************************/
110
111 static void api_ws_server_event_add(void *closure, const char *event, int eventid);
112 static void api_ws_server_event_remove(void *closure, const char *event, int eventid);
113 static void api_ws_server_event_push(void *closure, const char *event, int eventid, struct json_object *object);
114 static void api_ws_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object);
115
116 /* the interface for events pushing */
117 static const struct afb_evt_itf api_ws_server_evt_itf = {
118         .broadcast = api_ws_server_event_broadcast,
119         .push = api_ws_server_event_push,
120         .add = api_ws_server_event_add,
121         .remove = api_ws_server_event_remove
122 };
123
124 /******************* handling subcalls *****************************/
125
126 /**
127  * Structure on server side for recording pending
128  * subcalls.
129  */
130 struct api_ws_subcall
131 {
132         struct api_ws_subcall *next;    /**< next subcall for the client */
133         uint32_t subcallid;             /**< the subcallid */
134         void (*callback)(void*, int, struct json_object*); /**< callback on completion */
135         void *closure;                  /**< closure of the callback */
136 };
137
138 /**
139  * Structure for sending back replies on client side
140  */
141 struct api_ws_reply
142 {
143         struct api_ws *apiws;   /**< api descriptor */
144         uint32_t subcallid;     /**< subcallid for the reply */
145 };
146
147 /******************* client description part for server *****************************/
148
149 struct api_ws_client
150 {
151         /* the server ws-api */
152         const char *api;
153
154         /* count of references */
155         int refcount;
156
157         /* file descriptor */
158         int fd;
159
160         /* resource control */
161         pthread_mutex_t mutex;
162
163         /* listener for events */
164         struct afb_evt_listener *listener;
165
166         /* websocket */
167         struct afb_ws *ws;
168
169         /* credentials */
170         struct afb_cred *cred;
171
172         /* pending subcalls */
173         struct api_ws_subcall *subcalls;
174
175         /* apiset */
176         struct afb_apiset *apiset;
177 };
178
179 /******************* websocket interface for client part **********************************/
180
181 static void api_ws_server_on_binary(void *closure, char *data, size_t size);
182 static void api_ws_server_on_hangup(void *closure);
183
184 static const struct afb_ws_itf api_ws_server_ws_itf =
185 {
186         .on_close = NULL,
187         .on_text = NULL,
188         .on_binary = api_ws_server_on_binary,
189         .on_error = NULL,
190         .on_hangup = api_ws_server_on_hangup
191 };
192
193 /******************* ws request part for server *****************/
194
195 /*
196  * structure for a ws request
197  */
198 struct api_ws_server_req {
199         struct afb_xreq xreq;           /* the xreq */
200         struct api_ws_client *client;   /* the client of the request */
201         uint32_t msgid;                 /* the incoming request msgid */
202 };
203
204 static void api_ws_server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info);
205 static void api_ws_server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info);
206 static void api_ws_server_req_destroy_cb(struct afb_xreq *xreq);
207 static int api_ws_server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event event);
208 static int api_ws_server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event event);
209 static void api_ws_server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure);
210
211 const struct afb_xreq_query_itf afb_api_ws_xreq_itf = {
212         .success = api_ws_server_req_success_cb,
213         .fail = api_ws_server_req_fail_cb,
214         .unref = api_ws_server_req_destroy_cb,
215         .subcall = api_ws_server_req_subcall_cb,
216         .subscribe = api_ws_server_req_subscribe_cb,
217         .unsubscribe = api_ws_server_req_unsubscribe_cb
218 };
219
220 /******************* common part **********************************/
221
222 /*
223  * create a structure api_ws not connected to the 'path'.
224  */
225 static struct api_ws *api_ws_make(const char *path)
226 {
227         struct api_ws *api;
228         size_t length;
229
230         /* allocates the structure */
231         length = strlen(path);
232         api = calloc(1, sizeof *api + 1 + length);
233         if (api == NULL) {
234                 errno = ENOMEM;
235                 goto error;
236         }
237
238         /* path is copied after the struct */
239         api->path = (char*)(api+1);
240         memcpy(api->path, path, length + 1);
241
242         /* api name is at the end of the path */
243         while (length && path[length - 1] != '/' && path[length - 1] != ':')
244                 length = length - 1;
245         api->api = &api->path[length];
246         if (api->api == NULL || !afb_api_is_valid_name(api->api)) {
247                 errno = EINVAL;
248                 goto error2;
249         }
250         pthread_mutex_init(&api->mutex, NULL);
251
252         api->fd = -1;
253         return api;
254
255 error2:
256         free(api);
257 error:
258         return NULL;
259 }
260
261 static int api_ws_socket_unix(const char *path, int server)
262 {
263         int fd, rc;
264         struct sockaddr_un addr;
265         size_t length;
266
267         length = strlen(path);
268         if (length >= 108) {
269                 errno = ENAMETOOLONG;
270                 return -1;
271         }
272
273         if (server)
274                 unlink(path);
275
276         fd = socket(AF_UNIX, SOCK_STREAM, 0);
277         if (fd < 0)
278                 return fd;
279
280         memset(&addr, 0, sizeof addr);
281         addr.sun_family = AF_UNIX;
282         strcpy(addr.sun_path, path);
283         if (server) {
284                 rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
285         } else {
286                 rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
287         }
288         if (rc < 0) {
289                 close(fd);
290                 return rc;
291         }
292         return fd;
293 }
294
295 static int api_ws_socket_inet(const char *path, int server)
296 {
297         int rc, fd;
298         const char *service, *host, *api;
299         struct addrinfo hint, *rai, *iai;
300
301         /* scan the uri */
302         api = strrchr(path, '/');
303         service = strrchr(path, ':');
304         if (api == NULL || service == NULL || api < service) {
305                 errno = EINVAL;
306                 return -1;
307         }
308         host = strndupa(path, service++ - path);
309         service = strndupa(service, api - service);
310
311         /* get addr */
312         memset(&hint, 0, sizeof hint);
313         hint.ai_family = AF_INET;
314         hint.ai_socktype = SOCK_STREAM;
315         rc = getaddrinfo(host, service, &hint, &rai);
316         if (rc != 0) {
317                 errno = EINVAL;
318                 return -1;
319         }
320
321         /* get the socket */
322         iai = rai;
323         while (iai != NULL) {
324                 fd = socket(iai->ai_family, iai->ai_socktype, iai->ai_protocol);
325                 if (fd >= 0) {
326                         if (server) {
327                                 rc = bind(fd, iai->ai_addr, iai->ai_addrlen);
328                         } else {
329                                 rc = connect(fd, iai->ai_addr, iai->ai_addrlen);
330                         }
331                         if (rc == 0) {
332                                 freeaddrinfo(rai);
333                                 return fd;
334                         }
335                         close(fd);
336                 }
337                 iai = iai->ai_next;
338         }
339         freeaddrinfo(rai);
340         return -1;
341         
342 }
343
344 static int api_ws_socket(const char *path, int server)
345 {
346         int fd, rc;
347
348         /* check for systemd socket */
349         if (0 == strncmp(path, "sd:", 3))
350                 fd = sd_fds_for(path + 3);
351         else {
352                 /* check for unix socket */
353                 if (0 == strncmp(path, "unix:", 5))
354                         /* unix socket */
355                         fd = api_ws_socket_unix(path + 5, server);
356                 else
357                         /* inet socket */
358                         fd = api_ws_socket_inet(path, server);
359
360                 if (fd >= 0 && server) {
361                         rc = 1;
362                         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof rc);
363                         rc = listen(fd, 5);
364                 }
365         }
366         /* configure the socket */
367         if (fd >= 0) {
368                 fcntl(fd, F_SETFD, FD_CLOEXEC);
369                 fcntl(fd, F_SETFL, O_NONBLOCK);
370         }
371         return fd;
372 }
373
374 /******************* serialisation part **********************************/
375
376 struct readbuf
377 {
378         char *head, *end;
379 };
380
381 #define WRITEBUF_COUNT_MAX  32
382 struct writebuf
383 {
384         struct iovec iovec[WRITEBUF_COUNT_MAX];
385         uint32_t uints[WRITEBUF_COUNT_MAX];
386         int count;
387 };
388
389 static char *api_ws_read_get(struct readbuf *rb, uint32_t length)
390 {
391         char *before = rb->head;
392         char *after = before + length;
393         if (after > rb->end)
394                 return 0;
395         rb->head = after;
396         return before;
397 }
398
399 static int api_ws_read_char(struct readbuf *rb, char *value)
400 {
401         if (rb->head >= rb->end)
402                 return 0;
403         *value = *rb->head++;
404         return 1;
405 }
406
407 static int api_ws_read_uint32(struct readbuf *rb, uint32_t *value)
408 {
409         char *after = rb->head + sizeof *value;
410         if (after > rb->end)
411                 return 0;
412         memcpy(value, rb->head, sizeof *value);
413         rb->head = after;
414         *value = le32toh(*value);
415         return 1;
416 }
417
418 static int api_ws_read_string(struct readbuf *rb, const char **value, size_t *length)
419 {
420         uint32_t len;
421         if (!api_ws_read_uint32(rb, &len) || !len)
422                 return 0;
423         if (length)
424                 *length = (size_t)(len - 1);
425         return (*value = api_ws_read_get(rb, len)) != NULL &&  rb->head[-1] == 0;
426 }
427
428 static int api_ws_read_object(struct readbuf *rb, struct json_object **object)
429 {
430         const char *string;
431         struct json_object *o;
432         int rc = api_ws_read_string(rb, &string, NULL);
433         if (rc) {
434                 o = json_tokener_parse(string);
435                 if (o == NULL && strcmp(string, "null"))
436                         o = json_object_new_string(string);
437                 *object = o;
438         }
439         return rc;
440 }
441
442 static int api_ws_write_put(struct writebuf *wb, const void *value, size_t length)
443 {
444         int i = wb->count;
445         if (i == WRITEBUF_COUNT_MAX)
446                 return 0;
447         wb->iovec[i].iov_base = (void*)value;
448         wb->iovec[i].iov_len = length;
449         wb->count = i + 1;
450         return 1;
451 }
452
453 static int api_ws_write_char(struct writebuf *wb, char value)
454 {
455         int i = wb->count;
456         if (i == WRITEBUF_COUNT_MAX)
457                 return 0;
458         *(char*)&wb->uints[i] = value;
459         wb->iovec[i].iov_base = &wb->uints[i];
460         wb->iovec[i].iov_len = 1;
461         wb->count = i + 1;
462         return 1;
463 }
464
465 static int api_ws_write_uint32(struct writebuf *wb, uint32_t value)
466 {
467         int i = wb->count;
468         if (i == WRITEBUF_COUNT_MAX)
469                 return 0;
470         wb->uints[i] = htole32(value);
471         wb->iovec[i].iov_base = &wb->uints[i];
472         wb->iovec[i].iov_len = sizeof wb->uints[i];
473         wb->count = i + 1;
474         return 1;
475 }
476
477 static int api_ws_write_string_length(struct writebuf *wb, const char *value, size_t length)
478 {
479         uint32_t len = (uint32_t)++length;
480         return (size_t)len == length && len && api_ws_write_uint32(wb, len) && api_ws_write_put(wb, value, length);
481 }
482
483 static int api_ws_write_string(struct writebuf *wb, const char *value)
484 {
485         return api_ws_write_string_length(wb, value, strlen(value));
486 }
487
488 static int api_ws_write_object(struct writebuf *wb, struct json_object *object)
489 {
490         const char *string = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN);
491         return string != NULL && api_ws_write_string(wb, string);
492 }
493
494 /******************* client part **********************************/
495
496 /*
497  * structure for recording query data
498  */
499 struct api_ws_memo {
500         struct api_ws_memo *next;       /* the next memo */
501         struct api_ws *api;             /* the ws api */
502         struct afb_xreq *xreq;          /* the request handle */
503         uint32_t msgid;                 /* the message identifier */
504 };
505
506 struct api_ws_event
507 {
508         struct api_ws_event *next;
509         struct afb_event event;
510         int eventid;
511         int refcount;
512 };
513
514 /* search a memorized request */
515 static struct api_ws_memo *api_ws_client_memo_search(struct api_ws *api, uint32_t msgid)
516 {
517         struct api_ws_memo *memo;
518
519         memo = api->client.memos;
520         while (memo != NULL && memo->msgid != msgid)
521                 memo = memo->next;
522
523         return memo;
524 }
525
526 /* search the event */
527 static struct api_ws_event *api_ws_client_event_search(struct api_ws *api, uint32_t eventid, const char *name)
528 {
529         struct api_ws_event *ev;
530
531         ev = api->client.events;
532         while (ev != NULL && (ev->eventid != eventid || 0 != strcmp(afb_evt_event_name(ev->event), name)))
533                 ev = ev->next;
534
535         return ev;
536 }
537
538
539 /* allocates and init the memorizing data */
540 static struct api_ws_memo *api_ws_client_memo_make(struct api_ws *api, struct afb_xreq *xreq)
541 {
542         struct api_ws_memo *memo;
543
544         memo = malloc(sizeof *memo);
545         if (memo != NULL) {
546                 afb_xreq_addref(xreq);
547                 memo->xreq = xreq;
548                 do { memo->msgid = ++api->client.id; } while(api_ws_client_memo_search(api, memo->msgid) != NULL);
549                 memo->api = api;
550                 memo->next = api->client.memos;
551                 api->client.memos = memo;
552         }
553         return memo;
554 }
555
556 /* free and release the memorizing data */
557 static void api_ws_client_memo_destroy(struct api_ws_memo *memo)
558 {
559         struct api_ws_memo **prv;
560
561         prv = &memo->api->client.memos;
562         while (*prv != NULL) {
563                 if (*prv == memo) {
564                         *prv = memo->next;
565                         break;
566                 }
567                 prv = &(*prv)->next;
568         }
569
570         afb_xreq_unref(memo->xreq);
571         free(memo);
572 }
573
574 /* get event data from the message */
575 static int api_ws_client_msg_event_read(struct readbuf *rb, uint32_t *eventid, const char **name)
576 {
577         return api_ws_read_uint32(rb, eventid) && api_ws_read_string(rb, name, NULL);
578 }
579
580 /* get event from the message */
581 static int api_ws_client_msg_event_get(struct api_ws *api, struct readbuf *rb, struct api_ws_event **ev)
582 {
583         const char *name;
584         uint32_t eventid;
585
586         /* get event data from the message */
587         if (!api_ws_client_msg_event_read(rb, &eventid, &name)) {
588                 ERROR("Invalid message");
589                 return 0;
590         }
591
592         /* check conflicts */
593         *ev = api_ws_client_event_search(api, eventid, name);
594         if (*ev == NULL) {
595                 ERROR("event %s not found", name);
596                 return 0;
597         }
598
599         return 1;
600 }
601
602 /* get event from the message */
603 static int api_ws_client_msg_memo_get(struct api_ws *api, struct readbuf *rb, struct api_ws_memo **memo)
604 {
605         uint32_t msgid;
606
607         /* get event data from the message */
608         if (!api_ws_read_uint32(rb, &msgid)) {
609                 ERROR("Invalid message");
610                 return 0;
611         }
612
613         /* get the memo */
614         *memo = api_ws_client_memo_search(api, msgid);
615         if (*memo == NULL) {
616                 ERROR("message not found");
617                 return 0;
618         }
619
620         return 1;
621 }
622
623 /* read a subscrition message */
624 static int api_ws_client_msg_subscription_get(struct api_ws *api, struct readbuf *rb, struct api_ws_memo **memo, struct api_ws_event **ev)
625 {
626         return api_ws_client_msg_memo_get(api, rb, memo) && api_ws_client_msg_event_get(api, rb, ev);
627 }
628
629 /* adds an event */
630 static void api_ws_client_event_create(struct api_ws *api, struct readbuf *rb)
631 {
632         size_t offset;
633         const char *name;
634         uint32_t eventid;
635         struct api_ws_event *ev;
636
637         /* get event data from the message */
638         offset = api_ws_client_msg_event_read(rb, &eventid, &name);
639         if (offset == 0) {
640                 ERROR("Invalid message");
641                 return;
642         }
643
644         /* check conflicts */
645         ev = api_ws_client_event_search(api, eventid, name);
646         if (ev != NULL) {
647                 ev->refcount++;
648                 return;
649         }
650
651         /* no conflict, try to add it */
652         ev = malloc(sizeof *ev);
653         if (ev != NULL) {
654                 ev->event = afb_evt_create_event(name);
655                 if (ev->event.closure == NULL)
656                         free(ev);
657                 else {
658                         ev->refcount = 1;
659                         ev->eventid = eventid;
660                         ev->next = api->client.events;
661                         api->client.events = ev;
662                         return;
663                 }
664         }
665         ERROR("can't create event %s, out of memory", name);
666 }
667
668 /* removes an event */
669 static void api_ws_client_event_drop(struct api_ws *api, struct readbuf *rb)
670 {
671         struct api_ws_event *ev, **prv;
672
673         /* retrieves the event */
674         if (!api_ws_client_msg_event_get(api, rb, &ev))
675                 return;
676
677         /* decrease the reference count */
678         if (--ev->refcount)
679                 return;
680
681         /* unlinks the event */
682         prv = &api->client.events;
683         while (*prv != ev)
684                 prv = &(*prv)->next;
685         *prv = ev->next;
686
687         /* destroys the event */
688         afb_event_drop(ev->event);
689         free(ev);
690 }
691
692 /* subscribes an event */
693 static void api_ws_client_event_subscribe(struct api_ws *api, struct readbuf *rb)
694 {
695         struct api_ws_event *ev;
696         struct api_ws_memo *memo;
697
698         if (api_ws_client_msg_subscription_get(api, rb, &memo, &ev)) {
699                 /* subscribe the request from the event */
700                 if (afb_xreq_subscribe(memo->xreq, ev->event) < 0)
701                         ERROR("can't subscribe: %m");
702         }
703 }
704
705 /* unsubscribes an event */
706 static void api_ws_client_event_unsubscribe(struct api_ws *api, struct readbuf *rb)
707 {
708         struct api_ws_event *ev;
709         struct api_ws_memo *memo;
710
711         if (api_ws_client_msg_subscription_get(api, rb, &memo, &ev)) {
712                 /* unsubscribe the request from the event */
713                 if (afb_xreq_unsubscribe(memo->xreq, ev->event) < 0)
714                         ERROR("can't unsubscribe: %m");
715         }
716 }
717
718 /* receives broadcasted events */
719 static void api_ws_client_event_broadcast(struct api_ws *api, struct readbuf *rb)
720 {
721         struct json_object *object;
722         const char *event;
723
724         if (api_ws_read_string(rb, &event, NULL) && api_ws_read_object(rb, &object))
725                 afb_evt_broadcast(event, object);
726         else
727                 ERROR("unreadable broadcasted event");
728 }
729
730 /* pushs an event */
731 static void api_ws_client_event_push(struct api_ws *api, struct readbuf *rb)
732 {
733         struct api_ws_event *ev;
734         struct json_object *object;
735
736         if (api_ws_client_msg_event_get(api, rb, &ev) && api_ws_read_object(rb, &object))
737                 afb_event_push(ev->event, object);
738         else
739                 ERROR("unreadable push event");
740 }
741
742 static void api_ws_client_reply_success(struct api_ws *api, struct readbuf *rb)
743 {
744         struct api_ws_memo *memo;
745         struct json_object *object;
746         const char *info;
747         uint32_t flags;
748
749         /* retrieve the message data */
750         if (!api_ws_client_msg_memo_get(api, rb, &memo))
751                 return;
752
753         if (api_ws_read_uint32(rb, &flags)
754          && api_ws_read_string(rb, &info, NULL)
755          && api_ws_read_object(rb, &object)) {
756                 memo->xreq->context.flags = (unsigned)flags;
757                 afb_xreq_success(memo->xreq, object, *info ? info : NULL);
758         } else {
759                 /* failing to have the answer */
760                 afb_xreq_fail(memo->xreq, "error", "ws error");
761         }
762         api_ws_client_memo_destroy(memo);
763 }
764
765 static void api_ws_client_reply_fail(struct api_ws *api, struct readbuf *rb)
766 {
767         struct api_ws_memo *memo;
768         const char *info, *status;
769         uint32_t flags;
770
771         /* retrieve the message data */
772         if (!api_ws_client_msg_memo_get(api, rb, &memo))
773                 return;
774
775         if (api_ws_read_uint32(rb, &flags)
776          && api_ws_read_string(rb, &status, NULL)
777          && api_ws_read_string(rb, &info, NULL)) {
778                 memo->xreq->context.flags = (unsigned)flags;
779                 afb_xreq_fail(memo->xreq, status, *info ? info : NULL);
780         } else {
781                 /* failing to have the answer */
782                 afb_xreq_fail(memo->xreq, "error", "ws error");
783         }
784         api_ws_client_memo_destroy(memo);
785 }
786
787 /* send a subcall reply */
788 static void api_ws_client_send_subcall_reply(struct api_ws_reply *reply, int iserror, json_object *object)
789 {
790         int rc;
791         struct writebuf wb = { .count = 0 };
792         char ie = (char)!!iserror;
793
794         if (!api_ws_write_char(&wb, CHAR_FOR_SUBCALL_REPLY)
795          || !api_ws_write_uint32(&wb, reply->subcallid)
796          || !api_ws_write_char(&wb, ie)
797          || !api_ws_write_object(&wb, object)) {
798                 /* write error ? */
799                 return;
800         }
801
802         rc = afb_ws_binary_v(reply->apiws->client.ws, wb.iovec, wb.count);
803         if (rc >= 0)
804                 return;
805         ERROR("error while sending subcall reply");
806 }
807
808 /* callback for subcall reply */
809 static void api_ws_client_subcall_reply_cb(void *closure, int iserror, json_object *object)
810 {
811         api_ws_client_send_subcall_reply(closure, iserror, object);
812         free(closure);
813 }
814
815 /* received a subcall request */
816 static void api_ws_client_subcall(struct api_ws *apiws, struct readbuf *rb)
817 {
818         struct api_ws_reply *reply;
819         struct api_ws_memo *memo;
820         const char *api, *verb;
821         uint32_t subcallid;
822         struct json_object *object;
823
824         reply = malloc(sizeof *reply);
825         if (!reply)
826                 return;
827
828         /* retrieve the message data */
829         if (!api_ws_client_msg_memo_get(apiws, rb, &memo))
830                 return;
831
832         if (api_ws_read_uint32(rb, &subcallid)
833          && api_ws_read_string(rb, &api, NULL)
834          && api_ws_read_string(rb, &verb, NULL)
835          && api_ws_read_object(rb, &object)) {
836                 reply->apiws = apiws;
837                 reply->subcallid = subcallid;
838                 afb_xreq_subcall(memo->xreq, api, verb, object, api_ws_client_subcall_reply_cb, reply);
839         }
840 }
841
842 /* callback when receiving binary data */
843 static void api_ws_client_on_binary(void *closure, char *data, size_t size)
844 {
845         if (size > 0) {
846                 struct api_ws *apiws = closure;
847                 struct readbuf rb = { .head = data, .end = data + size };
848
849                 pthread_mutex_lock(&apiws->mutex);
850                 switch (*rb.head++) {
851                 case CHAR_FOR_ANSWER_SUCCESS: /* success */
852                         api_ws_client_reply_success(apiws, &rb);
853                         break;
854                 case CHAR_FOR_ANSWER_FAIL: /* fail */
855                         api_ws_client_reply_fail(apiws, &rb);
856                         break;
857                 case CHAR_FOR_EVT_BROADCAST: /* broadcast */
858                         api_ws_client_event_broadcast(apiws, &rb);
859                         break;
860                 case CHAR_FOR_EVT_ADD: /* creates the event */
861                         api_ws_client_event_create(apiws, &rb);
862                         break;
863                 case CHAR_FOR_EVT_DEL: /* drops the event */
864                         api_ws_client_event_drop(apiws, &rb);
865                         break;
866                 case CHAR_FOR_EVT_PUSH: /* pushs the event */
867                         api_ws_client_event_push(apiws, &rb);
868                         break;
869                 case CHAR_FOR_EVT_SUBSCRIBE: /* subscribe event for a request */
870                         api_ws_client_event_subscribe(apiws, &rb);
871                         break;
872                 case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */
873                         api_ws_client_event_unsubscribe(apiws, &rb);
874                         break;
875                 case CHAR_FOR_SUBCALL_CALL: /* subcall */
876                         api_ws_client_subcall(apiws, &rb);
877                         break;
878                 default: /* unexpected message */
879                         /* TODO: close the connection */
880                         break;
881                 }
882                 pthread_mutex_unlock(&apiws->mutex);
883         }
884         free(data);
885 }
886
887 /* on call, propagate it to the ws service */
888 static void api_ws_client_call_cb(void * closure, struct afb_xreq *xreq)
889 {
890         int rc;
891         struct api_ws_memo *memo;
892         struct writebuf wb = { .count = 0 };
893         const char *raw;
894         size_t szraw;
895         struct api_ws *apiws = closure;
896
897         pthread_mutex_lock(&apiws->mutex);
898
899         /* create the recording data */
900         memo = api_ws_client_memo_make(apiws, xreq);
901         if (memo == NULL) {
902                 afb_xreq_fail_f(xreq, "error", "out of memory");
903                 goto end;
904         }
905
906         /* creates the call message */
907         raw = afb_xreq_raw(xreq, &szraw);
908         if (raw == NULL)
909                 goto internal_error;
910         if (!api_ws_write_char(&wb, CHAR_FOR_CALL)
911          || !api_ws_write_uint32(&wb, memo->msgid)
912          || !api_ws_write_uint32(&wb, (uint32_t)xreq->context.flags)
913          || !api_ws_write_string(&wb, xreq->verb)
914          || !api_ws_write_string(&wb, afb_session_uuid(xreq->context.session))
915          || !api_ws_write_string_length(&wb, raw, szraw))
916                 goto overflow;
917
918         /* send */
919         rc = afb_ws_binary_v(apiws->client.ws, wb.iovec, wb.count);
920         if (rc >= 0)
921                 goto end;
922
923         afb_xreq_fail(xreq, "error", "websocket sending error");
924         goto clean_memo;
925
926 internal_error:
927         afb_xreq_fail(xreq, "error", "internal: raw is NULL!");
928         goto clean_memo;
929
930 overflow:
931         afb_xreq_fail(xreq, "error", "overflow: size doesn't match 32 bits!");
932
933 clean_memo:
934         api_ws_client_memo_destroy(memo);
935 end:
936         pthread_mutex_unlock(&apiws->mutex);
937 }
938
939 /*  */
940 static void api_ws_client_disconnect(struct api_ws *api)
941 {
942         if (api->fd >= 0) {
943                 afb_ws_destroy(api->client.ws);
944                 api->client.ws = NULL;
945                 close(api->fd);
946                 api->fd = -1;
947         }
948 }
949
950 /*  */
951 static int api_ws_client_connect(struct api_ws *api)
952 {
953         struct afb_ws *ws;
954         int fd;
955
956         fd = api_ws_socket(api->path, 0);
957         if (fd >= 0) {
958                 ws = afb_ws_create(afb_common_get_event_loop(), fd, &api_ws_client_ws_itf, api);
959                 if (ws != NULL) {
960                         api->client.ws = ws;
961                         api->fd = fd;
962                         return 0;
963                 }
964                 close(fd);
965         }
966         return -1;
967 }
968
969 static struct afb_api_itf ws_api_itf = {
970         .call = api_ws_client_call_cb
971 };
972
973 /* adds a afb-ws-service client api */
974 int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset)
975 {
976         int rc;
977         struct api_ws *api;
978         struct afb_api afb_api;
979
980         /* create the ws client api */
981         api = api_ws_make(path);
982         if (api == NULL)
983                 goto error;
984
985         /* connect to the service */
986         rc = api_ws_client_connect(api);
987         if (rc < 0) {
988                 ERROR("can't connect to ws service %s", api->path);
989                 goto error2;
990         }
991
992         /* record it as an API */
993         afb_api.closure = api;
994         afb_api.itf = &ws_api_itf;
995         if (afb_apiset_add(apiset, api->api, afb_api) < 0)
996                 goto error3;
997
998         return 0;
999
1000 error3:
1001         api_ws_client_disconnect(api);
1002 error2:
1003         free(api);
1004 error:
1005         return -1;
1006 }
1007
1008 /******************* client description part for server *****************************/
1009
1010 static void api_ws_server_client_unref(struct api_ws_client *client)
1011 {
1012         struct api_ws_subcall *sc, *nsc;
1013
1014         if (!__atomic_sub_fetch(&client->refcount, 1, __ATOMIC_RELAXED)) {
1015                 afb_evt_listener_unref(client->listener);
1016                 afb_ws_destroy(client->ws);
1017                 nsc = client->subcalls;
1018                 while (nsc) {
1019                         sc= nsc;
1020                         nsc = sc->next;
1021                         sc->callback(sc->closure, 1, NULL);
1022                         free(sc);
1023                 }
1024                 afb_cred_unref(client->cred);
1025                 afb_apiset_unref(client->apiset);
1026                 free(client);
1027         }
1028 }
1029
1030 static void api_ws_server_client_addref(struct api_ws_client *client)
1031 {
1032         __atomic_add_fetch(&client->refcount, 1, __ATOMIC_RELAXED);
1033 }
1034
1035 /* on call, propagate it to the ws service */
1036 static void api_ws_server_on_call(struct api_ws_client *client, struct readbuf *rb)
1037 {
1038         struct api_ws_server_req *wreq;
1039         char *cverb;
1040         const char *uuid, *verb;
1041         uint32_t flags, msgid;
1042         size_t lenverb;
1043         struct json_object *object;
1044
1045         api_ws_server_client_addref(client);
1046
1047         /* reads the call message data */
1048         if (!api_ws_read_uint32(rb, &msgid)
1049          || !api_ws_read_uint32(rb, &flags)
1050          || !api_ws_read_string(rb, &verb, &lenverb)
1051          || !api_ws_read_string(rb, &uuid, NULL)
1052          || !api_ws_read_object(rb, &object))
1053                 goto overflow;
1054
1055         /* create the request */
1056         wreq = malloc(++lenverb + sizeof *wreq);
1057         if (wreq == NULL)
1058                 goto out_of_memory;
1059
1060         afb_xreq_init(&wreq->xreq, &afb_api_ws_xreq_itf);
1061         wreq->client = client;
1062         wreq->msgid = msgid;
1063         cverb = (char*)&wreq[1];
1064         memcpy(cverb, verb, lenverb);
1065
1066         /* init the context */
1067         if (afb_context_connect(&wreq->xreq.context, uuid, NULL) < 0)
1068                 goto unconnected;
1069         wreq->xreq.context.flags = flags;
1070
1071         /* makes the call */
1072         wreq->xreq.cred = afb_cred_addref(client->cred);
1073         wreq->xreq.api = client->api;
1074         wreq->xreq.verb = cverb;
1075         wreq->xreq.json = object;
1076         afb_xreq_process(&wreq->xreq, client->apiset);
1077         return;
1078
1079 unconnected:
1080         free(wreq);
1081 out_of_memory:
1082         json_object_put(object);
1083 overflow:
1084         api_ws_server_client_unref(client);
1085 }
1086
1087 /* on subcall reply */
1088 static void api_ws_server_on_subcall_reply(struct api_ws_client *client, struct readbuf *rb)
1089 {
1090         char iserror;
1091         uint32_t subcallid;
1092         struct json_object *object;
1093         struct api_ws_subcall *sc, **psc;
1094
1095         /* reads the call message data */
1096         if (!api_ws_read_uint32(rb, &subcallid)
1097          || !api_ws_read_char(rb, &iserror)
1098          || !api_ws_read_object(rb, &object)) {
1099                 /* TODO bad protocol */
1100                 return;
1101         }
1102
1103         /* search the subcall and unlink it */
1104         pthread_mutex_lock(&client->mutex);
1105         psc = &client->subcalls;
1106         while ((sc = *psc) && sc->subcallid != subcallid)
1107                 psc = &sc->next;
1108         if (!sc) {
1109                 pthread_mutex_unlock(&client->mutex);
1110                 /* TODO subcall not found */
1111         } else {
1112                 *psc = sc->next;
1113                 pthread_mutex_unlock(&client->mutex);
1114                 sc->callback(sc->closure, (int)iserror, object);
1115                 free(sc);
1116         }
1117         json_object_put(object);
1118 }
1119
1120 /* callback when receiving binary data */
1121 static void api_ws_server_on_binary(void *closure, char *data, size_t size)
1122 {
1123         if (size > 0) {
1124                 struct readbuf rb = { .head = data, .end = data + size };
1125                 switch (*rb.head++) {
1126                 case CHAR_FOR_CALL:
1127                         api_ws_server_on_call(closure, &rb);
1128                         break;
1129                 case CHAR_FOR_SUBCALL_REPLY:
1130                         api_ws_server_on_subcall_reply(closure, &rb);
1131                         break;
1132                 default: /* unexpected message */
1133                         /* TODO: close the connection */
1134                         break;
1135                 }
1136         }
1137         free(data);
1138 }
1139
1140 /* callback when receiving a hangup */
1141 static void api_ws_server_on_hangup(void *closure)
1142 {
1143         struct api_ws_client *client = closure;
1144
1145         /* close the socket */
1146         if (client->fd >= 0) {
1147                 close(client->fd);
1148                 client->fd = -1;
1149         }
1150
1151         /* release the client */
1152         api_ws_server_client_unref(client);
1153 }
1154
1155 static void api_ws_server_accept(struct api_ws *api)
1156 {
1157         struct api_ws_client *client;
1158         struct sockaddr addr;
1159         socklen_t lenaddr;
1160
1161         client = calloc(1, sizeof *client);
1162         if (client != NULL) {
1163                 client->listener = afb_evt_listener_create(&api_ws_server_evt_itf, client);
1164                 if (client->listener != NULL) {
1165                         lenaddr = (socklen_t)sizeof addr;
1166                         client->fd = accept(api->fd, &addr, &lenaddr);
1167                         if (client->fd >= 0) {
1168                                 client->cred = afb_cred_create_for_socket(client->fd);
1169                                 fcntl(client->fd, F_SETFD, FD_CLOEXEC);
1170                                 fcntl(client->fd, F_SETFL, O_NONBLOCK);
1171                                 client->ws = afb_ws_create(afb_common_get_event_loop(), client->fd, &api_ws_server_ws_itf, client);
1172                                 if (client->ws != NULL) {
1173                                         client->api = api->api;
1174                                         client->apiset = afb_apiset_addref(api->server.apiset);
1175                                         client->refcount = 1;
1176                                         client->subcalls = NULL;
1177                                         return;
1178                                 }
1179                                 afb_cred_unref(client->cred);
1180                                 close(client->fd);
1181                         }
1182                         afb_evt_listener_unref(client->listener);
1183                 }
1184                 free(client);
1185         }
1186 }
1187
1188 /******************* server part: manage events **********************************/
1189
1190 static void api_ws_server_event_send(struct api_ws_client *client, char order, const char *event, int eventid, const char *data)
1191 {
1192         int rc;
1193         struct writebuf wb = { .count = 0 };
1194
1195         if (api_ws_write_char(&wb, order)
1196          && api_ws_write_uint32(&wb, eventid)
1197          && api_ws_write_string(&wb, event)
1198          && (data == NULL || api_ws_write_string(&wb, data))) {
1199                 rc = afb_ws_binary_v(client->ws, wb.iovec, wb.count);
1200                 if (rc >= 0)
1201                         return;
1202         }
1203         ERROR("error while sending %c for event %s", order, event);
1204 }
1205
1206 static void api_ws_server_event_add(void *closure, const char *event, int eventid)
1207 {
1208         api_ws_server_event_send(closure, CHAR_FOR_EVT_ADD, event, eventid, NULL);
1209 }
1210
1211 static void api_ws_server_event_remove(void *closure, const char *event, int eventid)
1212 {
1213         api_ws_server_event_send(closure, CHAR_FOR_EVT_DEL, event, eventid, NULL);
1214 }
1215
1216 static void api_ws_server_event_push(void *closure, const char *event, int eventid, struct json_object *object)
1217 {
1218         const char *data = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN);
1219         api_ws_server_event_send(closure, CHAR_FOR_EVT_PUSH, event, eventid, data ? : "null");
1220         json_object_put(object);
1221 }
1222
1223 static void api_ws_server_event_broadcast(void *closure, const char *event, int eventid, struct json_object *object)
1224 {
1225         int rc;
1226         struct api_ws_client *client = closure;
1227
1228         struct writebuf wb = { .count = 0 };
1229
1230         if (api_ws_write_char(&wb, CHAR_FOR_EVT_BROADCAST) && api_ws_write_string(&wb, event) && api_ws_write_object(&wb, object)) {
1231                 rc = afb_ws_binary_v(client->ws, wb.iovec, wb.count);
1232                 if (rc < 0)
1233                         ERROR("error while broadcasting event %s", event);
1234         } else
1235                 ERROR("error while broadcasting event %s", event);
1236         json_object_put(object);
1237 }
1238
1239 /******************* ws request part for server *****************/
1240
1241 /* decrement the reference count of the request and free/release it on falling to null */
1242 static void api_ws_server_req_destroy_cb(struct afb_xreq *xreq)
1243 {
1244         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1245
1246         afb_context_disconnect(&wreq->xreq.context);
1247         afb_cred_unref(wreq->xreq.cred);
1248         json_object_put(wreq->xreq.json);
1249         api_ws_server_client_unref(wreq->client);
1250         free(wreq);
1251 }
1252
1253 static void api_ws_server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info)
1254 {
1255         int rc;
1256         struct writebuf wb = { .count = 0 };
1257         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1258
1259         if (api_ws_write_char(&wb, CHAR_FOR_ANSWER_SUCCESS)
1260          && api_ws_write_uint32(&wb, wreq->msgid)
1261          && api_ws_write_uint32(&wb, (uint32_t)wreq->xreq.context.flags)
1262          && api_ws_write_string(&wb, info ? : "")
1263          && api_ws_write_object(&wb, obj)) {
1264                 rc = afb_ws_binary_v(wreq->client->ws, wb.iovec, wb.count);
1265                 if (rc >= 0)
1266                         goto success;
1267         }
1268         ERROR("error while sending success");
1269 success:
1270         json_object_put(obj);
1271 }
1272
1273 static void api_ws_server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info)
1274 {
1275         int rc;
1276         struct writebuf wb = { .count = 0 };
1277         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1278
1279         if (api_ws_write_char(&wb, CHAR_FOR_ANSWER_FAIL)
1280          && api_ws_write_uint32(&wb, wreq->msgid)
1281          && api_ws_write_uint32(&wb, (uint32_t)wreq->xreq.context.flags)
1282          && api_ws_write_string(&wb, status)
1283          && api_ws_write_string(&wb, info ? : "")) {
1284                 rc = afb_ws_binary_v(wreq->client->ws, wb.iovec, wb.count);
1285                 if (rc >= 0)
1286                         return;
1287         }
1288         ERROR("error while sending fail");
1289 }
1290
1291 static void api_ws_server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure)
1292 {
1293         int rc;
1294         struct writebuf wb = { .count = 0 };
1295         struct api_ws_subcall *sc, *osc;
1296         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1297         struct api_ws_client *client = wreq->client;
1298
1299         sc = malloc(sizeof *sc);
1300         if (!sc) {
1301
1302         } else {
1303                 sc->callback = callback;
1304                 sc->closure = cb_closure;
1305
1306                 pthread_mutex_unlock(&client->mutex);
1307                 sc->subcallid = (uint32_t)(((intptr_t)sc) >> 6);
1308                 do {
1309                         sc->subcallid++;
1310                         osc = client->subcalls;
1311                         while(osc && osc->subcallid != sc->subcallid)
1312                                 osc = osc->next;
1313                 } while (osc);
1314                 sc->next = client->subcalls;
1315                 client->subcalls = sc;
1316                 pthread_mutex_unlock(&client->mutex);
1317
1318                 if (api_ws_write_char(&wb, CHAR_FOR_SUBCALL_CALL)
1319                  && api_ws_write_uint32(&wb, wreq->msgid)
1320                  && api_ws_write_uint32(&wb, sc->subcallid)
1321                  && api_ws_write_string(&wb, api)
1322                  && api_ws_write_string(&wb, verb)
1323                  && api_ws_write_object(&wb, args)) {
1324                         rc = afb_ws_binary_v(wreq->client->ws, wb.iovec, wb.count);
1325                         if (rc >= 0)
1326                                 return;
1327                 }
1328                 ERROR("error while sending fail");
1329         }
1330 }
1331
1332 static int api_ws_server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event event)
1333 {
1334         int rc, rc2;
1335         struct writebuf wb = { .count = 0 };
1336         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1337
1338         rc = afb_evt_add_watch(wreq->client->listener, event);
1339         if (rc < 0)
1340                 return rc;
1341
1342         if (api_ws_write_char(&wb, CHAR_FOR_EVT_SUBSCRIBE)
1343          && api_ws_write_uint32(&wb, wreq->msgid)
1344          && api_ws_write_uint32(&wb, (uint32_t)afb_evt_event_id(event))
1345          && api_ws_write_string(&wb, afb_evt_event_name(event))) {
1346                 rc2 = afb_ws_binary_v(wreq->client->ws, wb.iovec, wb.count);
1347                 if (rc2 >= 0)
1348                         goto success;
1349         }
1350         ERROR("error while subscribing event");
1351 success:
1352         return rc;
1353 }
1354
1355 static int api_ws_server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event event)
1356 {
1357         int rc, rc2;
1358         struct writebuf wb = { .count = 0 };
1359         struct api_ws_server_req *wreq = CONTAINER_OF_XREQ(struct api_ws_server_req, xreq);
1360
1361         if (api_ws_write_char(&wb, CHAR_FOR_EVT_UNSUBSCRIBE)
1362          && api_ws_write_uint32(&wb, wreq->msgid)
1363          && api_ws_write_uint32(&wb, (uint32_t)afb_evt_event_id(event))
1364          && api_ws_write_string(&wb, afb_evt_event_name(event))) {
1365                 rc2 = afb_ws_binary_v(wreq->client->ws, wb.iovec, wb.count);
1366                 if (rc2 >= 0)
1367                         goto success;
1368         }
1369         ERROR("error while subscribing event");
1370 success:
1371         rc = afb_evt_remove_watch(wreq->client->listener, event);
1372         return rc;
1373 }
1374
1375 /******************* server part **********************************/
1376
1377 static int api_ws_server_connect(struct api_ws *api);
1378
1379 static int api_ws_server_listen_callback(sd_event_source *src, int fd, uint32_t revents, void *closure)
1380 {
1381         if ((revents & EPOLLIN) != 0)
1382                 api_ws_server_accept(closure);
1383         if ((revents & EPOLLHUP) != 0)
1384                 api_ws_server_connect(closure);
1385         return 0;
1386 }
1387
1388 static void api_ws_server_disconnect(struct api_ws *api)
1389 {
1390         if (api->server.listensrc != NULL) {
1391                 sd_event_source_unref(api->server.listensrc);
1392                 api->server.listensrc = NULL;
1393         }
1394         if (api->fd >= 0) {
1395                 close(api->fd);
1396                 api->fd = -1;
1397         }
1398 }
1399
1400 static int api_ws_server_connect(struct api_ws *api)
1401 {
1402         int rc;
1403
1404         /* ensure disconnected */
1405         api_ws_server_disconnect(api);
1406
1407         /* request the service object name */
1408         api->fd = api_ws_socket(api->path, 1);
1409         if (api->fd < 0)
1410                 ERROR("can't create socket %s", api->path);
1411         else {
1412                 /* listen for service */
1413                 rc = sd_event_add_io(afb_common_get_event_loop(), &api->server.listensrc, api->fd, EPOLLIN, api_ws_server_listen_callback, api);
1414                 if (rc >= 0)
1415                         return 0;
1416                 close(api->fd);
1417                 errno = -rc;
1418                 ERROR("can't add ws object %s", api->path);
1419         }
1420         return -1;
1421 }
1422
1423 /* create the service */
1424 int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset)
1425 {
1426         int rc;
1427         struct api_ws *api;
1428
1429         /* creates the ws api object */
1430         api = api_ws_make(path);
1431         if (api == NULL)
1432                 goto error;
1433
1434         /* connect for serving */
1435         rc = api_ws_server_connect(api);
1436         if (rc < 0)
1437                 goto error2;
1438
1439         api->server.apiset = afb_apiset_addref(apiset);
1440         return 0;
1441
1442 error2:
1443         free(api);
1444 error:
1445         return -1;
1446 }
1447
1448