fdev: Introduce fdev for file event handling
authorJosé Bollo <jose.bollo@iot.bzh>
Thu, 22 Feb 2018 12:22:48 +0000 (13:22 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Thu, 22 Feb 2018 12:22:48 +0000 (13:22 +0100)
This is an effort to keep cutting dependency to systemd.

Change-Id: I9a0c032a1095e297c7f3ac5b67827fda3658b8d9
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
26 files changed:
src/CMakeLists.txt
src/afb-api-ws.c
src/afb-fdev.c [new file with mode: 0644]
src/afb-fdev.h [new file with mode: 0644]
src/afb-proto-ws.c
src/afb-proto-ws.h
src/afb-stub-ws.c
src/afb-stub-ws.h
src/afb-supervision.c
src/afb-systemd.c
src/afb-systemd.h
src/afb-websock.c
src/afb-ws-client.c
src/afb-ws-json1.c
src/afb-ws-json1.h
src/afb-ws.c
src/afb-ws.h
src/afb-wsj1.c
src/afb-wsj1.h
src/afs-supervisor.c
src/fdev-epoll.c [new file with mode: 0644]
src/fdev-epoll.h [new file with mode: 0644]
src/fdev-systemd.c [new file with mode: 0644]
src/fdev-systemd.h [new file with mode: 0644]
src/fdev.c [new file with mode: 0644]
src/fdev.h [new file with mode: 0644]

index 4ef8785..f72d312 100644 (file)
@@ -42,6 +42,7 @@ ADD_LIBRARY(afb-lib STATIC
        afb-debug.c
        afb-evt.c
        afb-export.c
+       afb-fdev.c
        afb-hook.c
        afb-hreq.c
        afb-hsrv.c
@@ -61,6 +62,9 @@ ADD_LIBRARY(afb-lib STATIC
        afb-ws.c
        afb-wsj1.c
        afb-xreq.c
+       fdev.c
+       fdev-epoll.c
+       fdev-systemd.c
        jobs.c
        locale-root.c
        process-name.c
@@ -96,7 +100,7 @@ INSTALL(TARGETS afs-supervisor
 ###########################################
 # build and install libafbwsc
 ###########################################
-ADD_LIBRARY(afbwsc SHARED afb-ws.c afb-ws-client.c afb-wsj1.c websock.c afb-proto-ws.c jobs-fake.c)
+ADD_LIBRARY(afbwsc SHARED afb-ws.c afb-ws-client.c afb-wsj1.c websock.c afb-proto-ws.c jobs-fake.c fdev.c fdev-systemd.c)
 SET_TARGET_PROPERTIES(afbwsc PROPERTIES
        VERSION ${LIBAFBWSC_VERSION}
        SOVERSION ${LIBAFBWSC_SOVERSION})
index 7fbe5be..489b43b 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include <systemd/sd-event.h>
+#include "afb-fdev.h"
+#include "afb-systemd.h"
 #include "afb-api.h"
 #include "afb-apiset.h"
-#include "afb-systemd.h"
 #include "afb-stub-ws.h"
 #include "verbose.h"
+#include "fdev.h"
 
 struct api_ws
 {
        char *path;             /* path of the object for the API */
        char *api;              /* api name of the interface */
-       int fd;                 /* file descriptor */
-       sd_event_source *listensrc; /**< systemd source for server socket */
+       struct fdev *fdev;      /* fdev handler */
        struct afb_apiset *apiset;
 };
 
@@ -77,7 +77,6 @@ static struct api_ws *api_ws_make(const char *path)
                goto error2;
        }
 
-       api->fd = -1;
        return api;
 
 error2:
@@ -176,7 +175,7 @@ static int api_ws_socket(const char *path, int server)
 
        /* check for systemd socket */
        if (0 == strncmp(path, "sd:", 3))
-               fd = systemd_fds_for(path + 3);
+               fd = afb_systemd_fds_for(path + 3);
        else {
                /* check for unix socket */
                if (0 == strncmp(path, "unix:", 5))
@@ -200,6 +199,24 @@ static int api_ws_socket(const char *path, int server)
        return fd;
 }
 
+static struct fdev *api_ws_socket_fdev(const char *path, int server)
+{
+       int fd;
+       struct fdev *fdev;
+
+       fd = api_ws_socket(path, server);
+       if (fd < 0)
+               fdev = 0;
+       else {
+               fdev = afb_fdev_create(fd);
+               if (!fdev)
+                       close(fd);
+       }
+       if (!fdev)
+               ERROR("can't make %s socket for %s", server ? "server" : "client", path);
+       return fdev;
+}
+
 /**********************************************************************************/
 
 int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong)
@@ -213,27 +230,23 @@ int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int stron
                goto error;
 
        /* connect to the service */
-       apiws->fd = api_ws_socket(apiws->path, 0);
-       if (apiws->fd < 0) {
-               ERROR("can't connect to ws service %s", apiws->path);
+       apiws->fdev = api_ws_socket_fdev(apiws->path, 0);
+       if (!apiws->fdev)
                goto error2;
-       }
 
-       stubws = afb_stub_ws_create_client(apiws->fd, apiws->api, apiset);
+       stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, apiset);
        if (!stubws) {
                ERROR("can't setup client ws service to %s", apiws->path);
                goto error3;
        }
        if (afb_stub_ws_client_add(stubws, apiset) < 0) {
                ERROR("can't add the client to the apiset for service %s", apiws->path);
-               goto error4;
+               goto error3;
        }
        free(apiws);
        return 0;
-error4:
-       afb_stub_ws_unref(stubws);
 error3:
-       close(apiws->fd);
+       afb_stub_ws_unref(stubws);
 error2:
        free(apiws);
 error:
@@ -250,9 +263,9 @@ int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset)
        return afb_api_ws_add_client(path, apiset, 0);
 }
 
-static int api_ws_server_accept_client(struct api_ws *apiws, int fd)
+static int api_ws_server_accept_client(struct api_ws *apiws, struct fdev *fdev)
 {
-       return -!afb_stub_ws_create_server(fd, apiws->api, apiws->apiset);
+       return -!afb_stub_ws_create_server(fdev, apiws->api, apiws->apiset);
 }
 
 static void api_ws_server_accept(struct api_ws *apiws)
@@ -260,20 +273,28 @@ static void api_ws_server_accept(struct api_ws *apiws)
        int rc, fd;
        struct sockaddr addr;
        socklen_t lenaddr;
+       struct fdev *fdev;
 
        lenaddr = (socklen_t)sizeof addr;
-       fd = accept(apiws->fd, &addr, &lenaddr);
-       if (fd >= 0) {
-               rc = api_ws_server_accept_client(apiws, fd);
-               if (rc >= 0)
-                       return;
-               close(fd);
+       fd = accept(fdev_fd(apiws->fdev), &addr, &lenaddr);
+       if (fd < 0) {
+               ERROR("can't accept connection to %s: %m", apiws->path);
+       } else {
+               fdev = afb_fdev_create(fd);
+               if (!fdev) {
+                       ERROR("can't hold accepted connection to %s: %m", apiws->path);
+                       close(fd);
+               } else {
+                       rc = api_ws_server_accept_client(apiws, fdev);
+                       if (rc < 0)
+                               ERROR("can't serve accepted connection to %s: %m", apiws->path);
+               }
        }
 }
 
 static int api_ws_server_connect(struct api_ws *apiws);
 
-static int api_ws_server_listen_callback(sd_event_source *src, int fd, uint32_t revents, void *closure)
+static void api_ws_server_listen_callback(void *closure, uint32_t revents, struct fdev *fdev)
 {
        struct api_ws *apiws = closure;
 
@@ -281,42 +302,28 @@ static int api_ws_server_listen_callback(sd_event_source *src, int fd, uint32_t
                api_ws_server_accept(apiws);
        if ((revents & EPOLLHUP) != 0)
                api_ws_server_connect(apiws);
-       return 0;
 }
 
 static void api_ws_server_disconnect(struct api_ws *apiws)
 {
-       if (apiws->listensrc != NULL) {
-               sd_event_source_unref(apiws->listensrc);
-               apiws->listensrc = NULL;
-       }
-       if (apiws->fd >= 0) {
-               close(apiws->fd);
-               apiws->fd = -1;
-       }
+       fdev_unref(apiws->fdev);
+       apiws->fdev = 0;
 }
 
 static int api_ws_server_connect(struct api_ws *apiws)
 {
-       int rc;
-
        /* ensure disconnected */
        api_ws_server_disconnect(apiws);
 
        /* request the service object name */
-       apiws->fd = api_ws_socket(apiws->path, 1);
-       if (apiws->fd < 0)
+       apiws->fdev = api_ws_socket_fdev(apiws->path, 1);
+       if (!apiws->fdev)
                ERROR("can't create socket %s", apiws->path);
        else {
                /* listen for service */
-               rc = sd_event_add_io(afb_systemd_get_event_loop(),
-                               &apiws->listensrc, apiws->fd, EPOLLIN,
-                               api_ws_server_listen_callback, apiws);
-               if (rc >= 0)
-                       return 0;
-               close(apiws->fd);
-               errno = -rc;
-               ERROR("can't add ws object %s", apiws->path);
+               fdev_set_events(apiws->fdev, EPOLLIN);
+               fdev_set_callback(apiws->fdev, api_ws_server_listen_callback, apiws);
+               return 0;
        }
        return -1;
 }
diff --git a/src/afb-fdev.c b/src/afb-fdev.c
new file mode 100644 (file)
index 0000000..943c254
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "afb-systemd.h"
+#include "fdev.h"
+#include "fdev-systemd.h"
+
+struct fdev *afb_fdev_create(int fd)
+{
+       return fdev_systemd_create(afb_systemd_get_event_loop(), fd);
+}
+
diff --git a/src/afb-fdev.h b/src/afb-fdev.h
new file mode 100644 (file)
index 0000000..0f29a9f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct fdev;
+
+extern struct fdev *afb_fdev_create(int fd);
index ce7d75d..56669e5 100644 (file)
@@ -38,6 +38,7 @@
 #include "afb-msg-json.h"
 #include "afb-proto-ws.h"
 #include "jobs.h"
+#include "fdev.h"
 
 struct afb_proto_ws;
 
@@ -161,7 +162,7 @@ struct afb_proto_ws
        int refcount;
 
        /* file descriptor */
-       int fd;
+       struct fdev *fdev;
 
        /* resource control */
        pthread_mutex_t mutex;
@@ -1157,9 +1158,9 @@ static void on_hangup(void *closure)
                free(cd);
        }
 
-       if (protows->fd >= 0) {
-               close(protows->fd);
-               protows->fd = -1;
+       if (protows->fdev) {
+               fdev_unref(protows->fdev);
+               protows->fdev = 0;
                if (protows->on_hangup)
                        protows->on_hangup(protows->closure);
        }
@@ -1187,7 +1188,7 @@ static const struct afb_ws_itf server_ws_itf =
 
 /*****************************************************/
 
-static struct afb_proto_ws *afb_proto_ws_create(struct sd_event *eloop, int fd, const struct afb_proto_ws_server_itf *itfs, const struct afb_proto_ws_client_itf *itfc, void *closure, const struct afb_ws_itf *itf)
+static struct afb_proto_ws *afb_proto_ws_create(struct fdev *fdev, const struct afb_proto_ws_server_itf *itfs, const struct afb_proto_ws_client_itf *itfc, void *closure, const struct afb_ws_itf *itf)
 {
        struct afb_proto_ws *protows;
 
@@ -1195,11 +1196,11 @@ static struct afb_proto_ws *afb_proto_ws_create(struct sd_event *eloop, int fd,
        if (protows == NULL)
                errno = ENOMEM;
        else {
-               fcntl(fd, F_SETFD, FD_CLOEXEC);
-               fcntl(fd, F_SETFL, O_NONBLOCK);
-               protows->ws = afb_ws_create(eloop, fd, itf, protows);
+               fcntl(fdev_fd(fdev), F_SETFD, FD_CLOEXEC);
+               fcntl(fdev_fd(fdev), F_SETFL, O_NONBLOCK);
+               protows->ws = afb_ws_create(fdev, itf, protows);
                if (protows->ws != NULL) {
-                       protows->fd = fd;
+                       protows->fdev = fdev;
                        protows->refcount = 1;
                        protows->subcalls = NULL;
                        protows->closure = closure;
@@ -1213,14 +1214,14 @@ static struct afb_proto_ws *afb_proto_ws_create(struct sd_event *eloop, int fd,
        return NULL;
 }
 
-struct afb_proto_ws *afb_proto_ws_create_client(struct sd_event *eloop, int fd, const struct afb_proto_ws_client_itf *itf, void *closure)
+struct afb_proto_ws *afb_proto_ws_create_client(struct fdev *fdev, const struct afb_proto_ws_client_itf *itf, void *closure)
 {
-       return afb_proto_ws_create(eloop, fd, NULL, itf, closure, &proto_ws_client_ws_itf);
+       return afb_proto_ws_create(fdev, NULL, itf, closure, &proto_ws_client_ws_itf);
 }
 
-struct afb_proto_ws *afb_proto_ws_create_server(struct sd_event *eloop, int fd, const struct afb_proto_ws_server_itf *itf, void *closure)
+struct afb_proto_ws *afb_proto_ws_create_server(struct fdev *fdev, const struct afb_proto_ws_server_itf *itf, void *closure)
 {
-       return afb_proto_ws_create(eloop, fd, itf, NULL, closure, &server_ws_itf);
+       return afb_proto_ws_create(fdev, itf, NULL, closure, &server_ws_itf);
 }
 
 void afb_proto_ws_unref(struct afb_proto_ws *protows)
index 103e37a..cef7ead 100644 (file)
@@ -18,7 +18,7 @@
 
 #pragma once
 
-struct sd_event;
+struct fdev;
 struct afb_proto_ws;
 struct afb_proto_ws_call;
 struct afb_proto_ws_subcall;
@@ -47,8 +47,8 @@ struct afb_proto_ws_server_itf
        void (*on_describe)(void *closure, struct afb_proto_ws_describe *describe);
 };
 
-extern struct afb_proto_ws *afb_proto_ws_create_client(struct sd_event *eloop, int fd, const struct afb_proto_ws_client_itf *itf, void *closure);
-extern struct afb_proto_ws *afb_proto_ws_create_server(struct sd_event *eloop, int fd, const struct afb_proto_ws_server_itf *itf, void *closure);
+extern struct afb_proto_ws *afb_proto_ws_create_client(struct fdev *fdev, const struct afb_proto_ws_client_itf *itf, void *closure);
+extern struct afb_proto_ws *afb_proto_ws_create_server(struct fdev *fdev, const struct afb_proto_ws_server_itf *itf, void *closure);
 
 extern void afb_proto_ws_unref(struct afb_proto_ws *protows);
 extern void afb_proto_ws_addref(struct afb_proto_ws *protows);
index 0049c50..37607ee 100644 (file)
@@ -36,8 +36,6 @@
 
 #include <afb/afb-event.h>
 
-#include "afb-systemd.h"
-
 #include "afb-session.h"
 #include "afb-cred.h"
 #include "afb-api.h"
@@ -48,6 +46,7 @@
 #include "afb-evt.h"
 #include "afb-xreq.h"
 #include "verbose.h"
+#include "fdev.h"
 #include "jobs.h"
 
 struct afb_stub_ws;
@@ -661,7 +660,7 @@ static void on_hangup(void *closure)
 
 /*****************************************************/
 
-static struct afb_stub_ws *afb_stub_ws_create(int fd, const char *apiname, struct afb_apiset *apiset, int client)
+static struct afb_stub_ws *afb_stub_ws_create(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset, int client)
 {
        struct afb_stub_ws *stubws;
 
@@ -670,10 +669,11 @@ static struct afb_stub_ws *afb_stub_ws_create(int fd, const char *apiname, struc
                errno = ENOMEM;
        else {
                if (client)
-                       stubws->proto = afb_proto_ws_create_client(afb_systemd_get_event_loop(), fd, &client_itf, stubws);
+                       stubws->proto = afb_proto_ws_create_client(fdev, &client_itf, stubws);
                else
-                       stubws->proto = afb_proto_ws_create_server(afb_systemd_get_event_loop(), fd, &server_itf, stubws);
-               if (stubws->proto != NULL) {
+                       stubws->proto = afb_proto_ws_create_server(fdev, &server_itf, stubws);
+
+               if (stubws->proto) {
                        strcpy(stubws->apiname, apiname);
                        stubws->apiset = afb_apiset_addref(apiset);
                        stubws->refcount = 1;
@@ -682,21 +682,22 @@ static struct afb_stub_ws *afb_stub_ws_create(int fd, const char *apiname, struc
                }
                free(stubws);
        }
+       fdev_unref(fdev);
        return NULL;
 }
 
-struct afb_stub_ws *afb_stub_ws_create_client(int fd, const char *apiname, struct afb_apiset *apiset)
+struct afb_stub_ws *afb_stub_ws_create_client(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset)
 {
-       return afb_stub_ws_create(fd, apiname, apiset, 1);
+       return afb_stub_ws_create(fdev, apiname, apiset, 1);
 }
 
-struct afb_stub_ws *afb_stub_ws_create_server(int fd, const char *apiname, struct afb_apiset *apiset)
+struct afb_stub_ws *afb_stub_ws_create_server(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset)
 {
        struct afb_stub_ws *stubws;
 
-       stubws = afb_stub_ws_create(fd, apiname, apiset, 0);
+       stubws = afb_stub_ws_create(fdev, apiname, apiset, 0);
        if (stubws) {
-               stubws->cred = afb_cred_create_for_socket(fd);
+               stubws->cred = afb_cred_create_for_socket(fdev_fd(fdev));
                stubws->listener = afb_evt_listener_create(&server_evt_itf, stubws);
                if (stubws->listener != NULL)
                        return stubws;
index 4e07f98..3bb56fe 100644 (file)
 
 #pragma once
 
+struct fdev;
 struct afb_stub_ws;
 struct afb_apiset;
 struct afb_api;
 
-extern struct afb_stub_ws *afb_stub_ws_create_client(int fd, const char *apiname, struct afb_apiset *apiset);
+extern struct afb_stub_ws *afb_stub_ws_create_client(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset);
 
-extern struct afb_stub_ws *afb_stub_ws_create_server(int fd, const char *apiname, struct afb_apiset *apiset);
+extern struct afb_stub_ws *afb_stub_ws_create_server(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset);
 
 extern void afb_stub_ws_unref(struct afb_stub_ws *stubws);
 
index f41ca18..0f8a16b 100644 (file)
@@ -43,6 +43,7 @@
 #include "afs-supervision.h"
 #include "afb-stub-ws.h"
 #include "afb-debug.h"
+#include "afb-fdev.h"
 #include "verbose.h"
 #include "wrap-json.h"
 #include "jobs.h"
@@ -138,6 +139,7 @@ static void try_connect_supervisor()
        int fd;
        ssize_t srd;
        struct afs_supervision_initiator initiator;
+       struct fdev *fdev;
 
        /* get the mutex */
        pthread_mutex_lock(&mutex);
@@ -195,10 +197,15 @@ static void try_connect_supervisor()
        }
 
        /* make the supervisor link */
-       supervisor = afb_stub_ws_create_server(fd, supervision_apiname, supervision_apiset);
+       fdev = afb_fdev_create(fd);
+       if (!fdev) {
+               ERROR("Creation of fdev failed: %m");
+               goto end2;
+       }
+       supervisor = afb_stub_ws_create_server(fdev, supervision_apiname, supervision_apiset);
        if (!supervisor) {
                ERROR("Creation of supervisor failed: %m");
-               goto end2;
+               goto end;
        }
        afb_stub_ws_on_hangup(supervisor, on_supervisor_hangup);
 
index 575d9f1..fe47967 100644 (file)
@@ -80,14 +80,14 @@ static char **fds_names()
        return names;
 }
 
-int systemd_fds_init()
+int afb_systemd_fds_init()
 {
        errno = 0;
        fds_names();
        return -!!errno;
 }
 
-int systemd_fds_for(const char *name)
+int afb_systemd_fds_for(const char *name)
 {
        int idx;
        char **names;
index ae8d61b..bf0c6a9 100644 (file)
@@ -24,7 +24,7 @@ extern struct sd_event *afb_systemd_get_event_loop();
 extern struct sd_bus *afb_systemd_get_user_bus();
 extern struct sd_bus *afb_systemd_get_system_bus();
 
-extern int systemd_fds_init();
-extern int systemd_fds_for(const char *name);
+extern int afb_systemd_fds_init();
+extern int afb_systemd_fds_for(const char *name);
 
 
index 799b2bd..e062cf7 100644 (file)
@@ -30,6 +30,7 @@
 #include "afb-hreq.h"
 #include "afb-websock.h"
 #include "afb-ws-json1.h"
+#include "afb-fdev.h"
 
 /**************** WebSocket connection upgrade ****************************/
 
@@ -94,7 +95,7 @@ static int headerhas(const char *header, const char *needle)
 struct protodef
 {
        const char *name;
-       void *(*create)(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure);
+       void *(*create)(struct fdev *fdev, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure);
 };
 
 static const struct protodef *search_proto(const struct protodef *protodefs, const char *protocols)
@@ -142,11 +143,18 @@ static void upgrade_to_websocket(
 {
        struct memo_websocket *memo = cls;
        void *ws;
+       struct fdev *fdev;
 
-       ws = memo->proto->create(sock, memo->apiset, &memo->hreq->xreq.context, close_websocket, urh);
-       if (ws == NULL) {
+       fdev = afb_fdev_create(sock);
+       if (!fdev) {
                /* TODO */
                close_websocket(urh);
+       } else {
+               ws = memo->proto->create(fdev, memo->apiset, &memo->hreq->xreq.context, close_websocket, urh);
+               if (ws == NULL) {
+                       /* TODO */
+                       close_websocket(urh);
+               }
        }
        afb_hreq_unref(memo->hreq);
        free(memo);
index e1d3277..7e1a04f 100644 (file)
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 
 #include "afb-wsj1.h"
+#include "fdev-systemd.h"
 
 /**************** WebSocket handshake ****************************/
 
@@ -320,6 +321,7 @@ struct afb_wsj1 *afb_ws_client_connect_wsj1(struct sd_event *eloop, const char *
        const char *path;
        struct addrinfo hint, *rai, *iai;
        struct afb_wsj1 *result;
+       struct fdev *fdev;
 
        /* scan the uri */
        rc = parse_uri(uri, &host, &service, &path);
@@ -354,10 +356,13 @@ struct afb_wsj1 *afb_ws_client_connect_wsj1(struct sd_event *eloop, const char *
                        if (rc == 0) {
                                rc = negociate(fd, proto_json1, path, xhost);
                                if (rc == 0) {
-                                       result = afb_wsj1_create(eloop, fd, itf, closure);
-                                       if (result != NULL) {
-                                               fcntl(fd, F_SETFL, O_NONBLOCK);
-                                               break;
+                                       fdev = fdev_systemd_create(eloop, fd);
+                                       if (fdev) {
+                                               result = afb_wsj1_create(fdev, itf, closure);
+                                               if (result != NULL) {
+                                                       fcntl(fd, F_SETFL, O_NONBLOCK);
+                                                       break;
+                                               }
                                        }
                                }
                        }
@@ -505,16 +510,18 @@ struct afb_proto_ws *afb_ws_client_connect_api(struct sd_event *eloop, const cha
 {
        int fd;
        struct afb_proto_ws *pws;
+       struct fdev *fdev;
 
        fd = get_socket(uri);
        if (fd >= 0) {
-               pws = afb_proto_ws_create_client(eloop, fd, itf, closure);
-               if (pws)
-                       return pws;
+               fdev = fdev_systemd_create(eloop, fd);
+               if (fdev) {
+                       pws = afb_proto_ws_create_client(fdev, itf, closure);
+                       if (pws)
+                               return pws;
+               }
                close(fd);
        }
        return NULL;
 }
 
-
-
index 0fa13df..68565aa 100644 (file)
@@ -36,6 +36,7 @@
 #include "afb-context.h"
 #include "afb-evt.h"
 #include "verbose.h"
+#include "fdev.h"
 
 /* predeclaration of structures */
 struct afb_ws_json1;
@@ -99,11 +100,11 @@ static const struct afb_evt_itf evt_itf = {
 ****************************************************************
 ***************************************************************/
 
-struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure)
+struct afb_ws_json1 *afb_ws_json1_create(struct fdev *fdev, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure)
 {
        struct afb_ws_json1 *result;
 
-       assert(fd >= 0);
+       assert(fdev);
        assert(context != NULL);
 
        result = malloc(sizeof * result);
@@ -118,7 +119,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, stru
        if (result->session == NULL)
                goto error2;
 
-       result->wsj1 = afb_wsj1_create(afb_systemd_get_event_loop(), fd, &wsj1_itf, result);
+       result->wsj1 = afb_wsj1_create(fdev, &wsj1_itf, result);
        if (result->wsj1 == NULL)
                goto error3;
 
@@ -126,7 +127,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, stru
        if (result->listener == NULL)
                goto error4;
 
-       result->cred = afb_cred_create_for_socket(fd);
+       result->cred = afb_cred_create_for_socket(fdev_fd(fdev));
        result->apiset = afb_apiset_addref(apiset);
        return result;
 
@@ -137,7 +138,7 @@ error3:
 error2:
        free(result);
 error:
-       close(fd);
+       fdev_unref(fdev);
        return NULL;
 }
 
index 96db1bc..024dd8c 100644 (file)
@@ -20,8 +20,9 @@
 struct afb_ws_json1;
 struct afb_context;
 struct afb_apiset;
+struct fdev;
 
-extern struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *closure);
+extern struct afb_ws_json1 *afb_ws_json1_create(struct fdev *fdev, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *closure);
 extern struct afb_ws_json1 *afb_ws_json1_addref(struct afb_ws_json1 *ws);
 extern void afb_ws_json1_unref(struct afb_ws_json1 *ws);
 
index c48a5e2..ef73add 100644 (file)
 #include <stdarg.h>
 #include <poll.h>
 
-#include <systemd/sd-event.h>
-
 #include "websock.h"
 #include "afb-ws.h"
-
-#include "afb-common.h"
+#include "fdev.h"
 
 /*
  * declaration of the websock interface for afb-ws
@@ -89,7 +86,7 @@ struct afb_ws
        const struct afb_ws_itf *itf; /* the callback interface */
        void *closure;          /* closure when calling the callbacks */
        struct websock *ws;     /* the websock handler */
-       sd_event_source *evsrc; /* the event source for the socket */
+       struct fdev *fdev;      /* the fdev for the socket */
        struct buf buffer;      /* the last read fragment */
 };
 
@@ -123,8 +120,7 @@ static void aws_disconnect(struct afb_ws *ws, int call_on_hangup)
        struct websock *wsi = ws->ws;
        if (wsi != NULL) {
                ws->ws = NULL;
-               sd_event_source_unref(ws->evsrc);
-               ws->evsrc = NULL;
+               fdev_unref(ws->fdev);
                websock_destroy(wsi);
                free(ws->buffer.buffer);
                ws->state = waiting;
@@ -133,13 +129,12 @@ static void aws_disconnect(struct afb_ws *ws, int call_on_hangup)
        }
 }
 
-static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *ws)
+static void fdevcb(void *ws, uint32_t revents, struct fdev *fdev)
 {
        if ((revents & EPOLLIN) != 0)
                aws_on_readable(ws);
        if ((revents & EPOLLHUP) != 0)
                afb_ws_hangup(ws);
-       return 0;
 }
 
 /*
@@ -151,12 +146,11 @@ static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, voi
  *
  * Returns the handle for the afb_ws created or NULL on error.
  */
-struct afb_ws *afb_ws_create(struct sd_event *eloop, int fd, const struct afb_ws_itf *itf, void *closure)
+struct afb_ws *afb_ws_create(struct fdev *fdev, const struct afb_ws_itf *itf, void *closure)
 {
-       int rc;
        struct afb_ws *result;
 
-       assert(fd >= 0);
+       assert(fdev);
 
        /* allocation */
        result = malloc(sizeof * result);
@@ -164,7 +158,8 @@ struct afb_ws *afb_ws_create(struct sd_event *eloop, int fd, const struct afb_ws
                goto error;
 
        /* init */
-       result->fd = fd;
+       result->fdev = fdev;
+       result->fd = fdev_fd(fdev);
        result->state = waiting;
        result->itf = itf;
        result->closure = closure;
@@ -176,19 +171,15 @@ struct afb_ws *afb_ws_create(struct sd_event *eloop, int fd, const struct afb_ws
        if (result->ws == NULL)
                goto error2;
 
-       /* creates the evsrc */
-       rc = sd_event_add_io(eloop, &result->evsrc, result->fd, EPOLLIN, io_event_callback, result);
-       if (rc < 0) {
-               errno = -rc;
-               goto error3;
-       }
+       /* finalize */
+       fdev_set_events(fdev, EPOLLIN);
+       fdev_set_callback(fdev, fdevcb, result);
        return result;
 
-error3:
-       websock_destroy(result->ws);
 error2:
        free(result);
 error:
+       fdev_unref(fdev);
        return NULL;
 }
 
index 4b26f0b..0af236e 100644 (file)
@@ -18,7 +18,7 @@
 #pragma once
 
 struct afb_ws;
-struct sd_event;
+struct fdev;
 struct iovec;
 
 struct afb_ws_itf
@@ -30,7 +30,7 @@ struct afb_ws_itf
        void (*on_hangup) (void *); /* optional, it is safe too call afb_ws_destroy within the callback */
 };
 
-extern struct afb_ws *afb_ws_create(struct sd_event *eloop, int fd, const struct afb_ws_itf *itf, void *closure);
+extern struct afb_ws *afb_ws_create(struct fdev *fdev, const struct afb_ws_itf *itf, void *closure);
 extern void afb_ws_destroy(struct afb_ws *ws);
 extern void afb_ws_hangup(struct afb_ws *ws);
 extern int afb_ws_is_connected(struct afb_ws *ws);
index be961f5..3876c32 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "afb-ws.h"
 #include "afb-wsj1.h"
+#include "fdev.h"
 
 #define CALL 2
 #define RETOK 3
@@ -81,12 +82,11 @@ struct afb_wsj1
        pthread_mutex_t mutex;
 };
 
-struct afb_wsj1 *afb_wsj1_create(struct sd_event *eloop, int fd, struct afb_wsj1_itf *itf, void *closure)
+struct afb_wsj1 *afb_wsj1_create(struct fdev *fdev, struct afb_wsj1_itf *itf, void *closure)
 {
        struct afb_wsj1 *result;
 
-       assert(eloop);
-       assert(fd >= 0);
+       assert(fdev);
        assert(itf);
        assert(itf->on_call);
 
@@ -103,7 +103,7 @@ struct afb_wsj1 *afb_wsj1_create(struct sd_event *eloop, int fd, struct afb_wsj1
        if (result->tokener == NULL)
                goto error2;
 
-       result->ws = afb_ws_create(eloop, fd, &wsj1_itf, result);
+       result->ws = afb_ws_create(fdev, &wsj1_itf, result);
        if (result->ws == NULL)
                goto error3;
 
@@ -114,7 +114,7 @@ error3:
 error2:
        free(result);
 error:
-       close(fd);
+       fdev_unref(fdev);
        return NULL;
 }
 
index 7e318f6..86c7cfd 100644 (file)
@@ -21,7 +21,7 @@ struct afb_wsj1;
 struct afb_wsj1_msg;
 
 struct json_object;
-struct sd_event;
+struct fdev;
 
 /*
  * Interface for callback functions.
@@ -48,13 +48,11 @@ struct afb_wsj1_itf {
 };
 
 /*
- * Creates the afb_wsj1 socket connected to the file descriptor 'fd'
+ * Creates the afb_wsj1 socket connected to the file descriptor 'fdev'
  * and having the callback interface defined by 'itf' for the 'closure'.
- * When the creation is a success, the systemd event loop 'eloop' is
- * used for handling event for 'fd'.
  * Returns the created wsj1 websocket or NULL in case of error.
  */
-extern struct afb_wsj1 *afb_wsj1_create(struct sd_event *eloop, int fd, struct afb_wsj1_itf *itf, void *closure);
+extern struct afb_wsj1 *afb_wsj1_create(struct fdev *fdev, struct afb_wsj1_itf *itf, void *closure);
 
 /*
  * Increases by one the count of reference to 'wsj1'
index be0cdbf..1e92b9f 100644 (file)
@@ -45,6 +45,7 @@
 #include "afb-api-so-v2.h"
 #include "afb-api-ws.h"
 #include "afb-apiset.h"
+#include "afb-fdev.h"
 #include "jobs.h"
 #include "verbose.h"
 #include "wrap-json.h"
@@ -193,13 +194,20 @@ static void on_supervised_hangup(struct afb_stub_ws *stub)
 static int make_supervised(int fd, struct afb_cred *cred)
 {
        struct supervised *s;
+       struct fdev *fdev;
 
        s = malloc(sizeof *s);
        if (!s)
                return -1;
 
+       fdev = afb_fdev_create(fd);
+       if (!fdev) {
+               free(s);
+               return -1;
+       }
+
        s->cred = cred;
-       s->stub = afb_stub_ws_create_client(fd, supervision_apiname, empty_apiset);
+       s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
        if (!s->stub) {
                free(s);
                return -1;
diff --git a/src/fdev-epoll.c b/src/fdev-epoll.c
new file mode 100644 (file)
index 0000000..80c037d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+
+#define FDEV_PROVIDER
+#include "fdev.h"
+#include "fdev-epoll.h"
+
+#define epollfd(fdev_epoll)  ((int)(intptr_t)fdev_epoll)
+
+static void disable(void *closure, const struct fdev *fdev)
+{
+       struct fdev_epoll *fdev_epoll = closure;
+       epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_DEL, fdev_fd(fdev), 0);
+}
+
+static void enable(void *closure, const struct fdev *fdev)
+{
+       struct fdev_epoll *fdev_epoll = closure;
+       struct epoll_event event;
+       int rc, fd;
+
+       fd = fdev_fd(fdev);
+       event.events = fdev_events(fdev);
+       event.data.ptr = (void*)fdev;
+       rc = epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_MOD, fd, &event);
+       if (rc < 0 && errno == ENOENT)
+               epoll_ctl(epollfd(fdev_epoll), EPOLL_CTL_ADD, fd, &event);
+}
+
+static struct fdev_itf itf =
+{
+       .unref = 0,
+       .disable = disable,
+       .enable = enable
+};
+
+struct fdev_epoll *fdev_epoll_create()
+{
+       int fd = epoll_create1(EPOLL_CLOEXEC);
+       if (!fd) {
+               fd = dup(fd);
+               close(0);
+       }
+       return fd < 0 ? 0 : (struct fdev_epoll*)(intptr_t)fd;
+}
+
+void fdev_epoll_destroy(struct fdev_epoll *fdev_epoll)
+{
+       close(epollfd(fdev_epoll));
+}
+
+int fdev_epoll_fd(struct fdev_epoll *fdev_epoll)
+{
+       return epollfd(fdev_epoll);
+}
+
+struct fdev *fdev_epoll_add(struct fdev_epoll *fdev_epoll, int fd)
+{
+       struct fdev *fdev;
+
+       fdev = fdev_create(fd);
+       if (fdev)
+               fdev_set_itf(fdev, &itf, fdev_epoll);
+       return fdev;
+}
+
+void fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms)
+{
+       struct fdev *fdev;
+       struct epoll_event events[8];
+       int rc, i;
+
+       rc = epoll_wait(epollfd(fdev_epoll), events, sizeof events / sizeof *events, timeout_ms < 0 ? -1 : timeout_ms);
+       for (i = 0 ; i < rc ; i++) {
+               fdev = events[i].data.ptr;
+               fdev_dispatch(fdev, events[i].events);
+       }
+}
+
diff --git a/src/fdev-epoll.h b/src/fdev-epoll.h
new file mode 100644 (file)
index 0000000..53d02e7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct fdev;
+struct fdev_epoll;
+
+extern struct fdev_epoll *fdev_epoll_create();
+extern void fdev_epoll_destroy(struct fdev_epoll *fdev_epoll);
+extern int fdev_epoll_fd(struct fdev_epoll *fdev_epoll);
+extern struct fdev *fdev_epoll_add(struct fdev_epoll *fdev_epoll, int fd);
+extern void fdev_epoll_wait_and_dispatch(struct fdev_epoll *fdev_epoll, int timeout_ms);
+
diff --git a/src/fdev-systemd.c b/src/fdev-systemd.c
new file mode 100644 (file)
index 0000000..0f4a03c
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+
+#include <systemd/sd-event.h>
+
+#define FDEV_PROVIDER
+#include "fdev.h"
+#include "fdev-systemd.h"
+
+static int handler(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+{
+       struct fdev *fdev = userdata;
+       fdev_dispatch(fdev, revents);
+       return 0;
+}
+
+static void unref(void *closure)
+{
+       sd_event_source *source = closure;
+       sd_event_source_unref(source);
+}
+
+static void disable(void *closure, const struct fdev *fdev)
+{
+       sd_event_source *source = closure;
+       sd_event_source_set_enabled(source, SD_EVENT_OFF);
+}
+
+static void enable(void *closure, const struct fdev *fdev)
+{
+       sd_event_source *source = closure;
+       sd_event_source_set_io_events(source, fdev_events(fdev));
+       sd_event_source_set_enabled(source, SD_EVENT_ON);
+}
+
+static struct fdev_itf itf =
+{
+       .unref = unref,
+       .disable = disable,
+       .enable = enable
+};
+
+struct fdev *fdev_systemd_create(struct sd_event *eloop, int fd)
+{
+       int rc;
+       sd_event_source *source;
+       struct fdev *fdev;
+
+       fdev = fdev_create(fd);
+       if (fdev) {
+               rc = sd_event_add_io(eloop, &source, fd, 0, handler, fdev);
+               if (rc < 0) {
+                       fdev_unref(fdev);
+                       fdev = 0;
+                       errno = -rc;
+               } else {
+                       sd_event_source_set_enabled(source, SD_EVENT_OFF);
+                       fdev_set_itf(fdev, &itf, source);
+               }
+       }
+       return fdev;
+}
+
diff --git a/src/fdev-systemd.h b/src/fdev-systemd.h
new file mode 100644 (file)
index 0000000..99ea5f1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+struct fdev;
+struct sd_event;
+
+extern struct fdev *fdev_systemd_create(struct sd_event *eloop, int fd);
diff --git a/src/fdev.c b/src/fdev.c
new file mode 100644 (file)
index 0000000..5c31d31
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FDEV_PROVIDER
+#include "fdev.h"
+
+struct fdev
+{
+       int fd;
+       uint32_t events;
+       int repeat;
+       unsigned refcount;
+       struct fdev_itf *itf;
+       void *closure_itf;
+       void (*callback)(void*,uint32_t,struct fdev*);
+       void *closure_callback;
+};
+
+struct fdev *fdev_create(int fd)
+{
+       struct fdev *fdev;
+
+       fdev = calloc(1, sizeof *fdev);
+       if (!fdev)
+               errno = ENOMEM;
+       else {
+               fdev->fd = fd;
+               fdev->refcount = 3; /* set autoclose by default */
+               fdev->repeat = -1;
+       }
+       return fdev;
+}
+
+void fdev_set_itf(struct fdev *fdev, struct fdev_itf *itf, void *closure_itf)
+{
+       fdev->itf = itf;
+       fdev->closure_itf = closure_itf;
+}
+
+void fdev_dispatch(struct fdev *fdev, uint32_t events)
+{
+       if (fdev->repeat > 0 && !--fdev->repeat && fdev->itf)
+               fdev->itf->disable(fdev->closure_itf, fdev);
+       if (fdev->callback)
+               fdev->callback(fdev->closure_callback, events, fdev);
+}
+
+struct fdev *fdev_addref(struct fdev *fdev)
+{
+       if (fdev)
+               __atomic_add_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED);
+       return fdev;
+}
+
+void fdev_unref(struct fdev *fdev)
+{
+       if (fdev && __atomic_sub_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED) <= 1) {
+               if (fdev->itf) {
+                       fdev->itf->disable(fdev->closure_itf, fdev);
+                       fdev->itf->unref(fdev->closure_itf);
+               }
+               if (fdev->refcount)
+                       close(fdev->fd);
+               free(fdev);
+       }
+}
+
+int fdev_fd(const struct fdev *fdev)
+{
+       return fdev->fd;
+}
+
+uint32_t fdev_events(const struct fdev *fdev)
+{
+       return fdev->events;
+}
+
+int fdev_repeat(const struct fdev *fdev)
+{
+       return fdev->repeat;
+}
+
+int fdev_autoclose(const struct fdev *fdev)
+{
+       return 1 & fdev->refcount;
+}
+
+static inline int is_active(struct fdev *fdev)
+{
+       return fdev->repeat && fdev->callback;
+}
+
+static inline void update_activity(struct fdev *fdev, int old_active)
+{
+       if (is_active(fdev)) {
+               if (!old_active)
+                       fdev->itf->enable(fdev->closure_itf, fdev);
+       } else {
+               if (old_active)
+                       fdev->itf->disable(fdev->closure_itf, fdev);
+       }
+}
+
+void fdev_set_callback(struct fdev *fdev, void (*callback)(void*,uint32_t,struct fdev*), void *closure)
+{
+       int oa;
+
+       oa = is_active(fdev);
+       fdev->callback = callback;
+       fdev->closure_callback = closure;
+       update_activity(fdev, oa);
+}
+
+void fdev_set_events(struct fdev *fdev, uint32_t events)
+{
+       if (events != fdev->events) {
+               fdev->events = events;
+               if (is_active(fdev))
+                       fdev->itf->enable(fdev->closure_itf, fdev);
+       }
+}
+
+void fdev_set_repeat(struct fdev *fdev, int count)
+{
+       int oa;
+
+       oa = is_active(fdev);
+       fdev->repeat = count;
+       update_activity(fdev, oa);
+}
+
+void fdev_set_autoclose(struct fdev *fdev, int autoclose)
+{
+       if (autoclose)
+               fdev->refcount |= 1;
+       else
+               fdev->refcount &= -2;
+}
+
diff --git a/src/fdev.h b/src/fdev.h
new file mode 100644 (file)
index 0000000..9fbcb75
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/epoll.h>
+
+struct fdev;
+
+#if defined(FDEV_PROVIDER)
+struct fdev_itf
+{
+       void (*unref)(void *closure);
+       void (*disable)(void *closure, const struct fdev *fdev);
+       void (*enable)(void *closure, const struct fdev *fdev);
+};
+
+extern struct fdev *fdev_create(int fd);
+extern void fdev_set_itf(struct fdev *fdev, struct fdev_itf *itf, void *closure_itf);
+extern void fdev_dispatch(struct fdev *fdev, uint32_t events);
+#endif
+
+extern struct fdev *fdev_addref(struct fdev *fdev);
+extern void fdev_unref(struct fdev *fdev);
+
+extern int fdev_fd(const struct fdev *fdev);
+extern uint32_t fdev_events(const struct fdev *fdev);
+extern int fdev_repeat(const struct fdev *fdev);
+extern int fdev_autoclose(const struct fdev *fdev);
+
+extern void fdev_set_callback(struct fdev *fdev, void (*callback)(void*,uint32_t,struct fdev*), void *closure);
+extern void fdev_set_events(struct fdev *fdev, uint32_t events);
+extern void fdev_set_repeat(struct fdev *fdev, int count);
+extern void fdev_set_autoclose(struct fdev *fdev, int autoclose);