aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2018-02-22 13:22:48 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2018-02-22 13:22:48 +0100
commitca820c65c2b03a24e8936218171c6c1d138fd1f7 (patch)
treef7e31ea8e63d3321af64226e360a78c504a09bb3
parentf15ea770dd9b13a20331853a026091316984f9ca (diff)
fdev: Introduce fdev for file event handling
This is an effort to keep cutting dependency to systemd. Change-Id: I9a0c032a1095e297c7f3ac5b67827fda3658b8d9 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/afb-api-ws.c97
-rw-r--r--src/afb-fdev.c26
-rw-r--r--src/afb-fdev.h22
-rw-r--r--src/afb-proto-ws.c27
-rw-r--r--src/afb-proto-ws.h6
-rw-r--r--src/afb-stub-ws.c23
-rw-r--r--src/afb-stub-ws.h5
-rw-r--r--src/afb-supervision.c11
-rw-r--r--src/afb-systemd.c4
-rw-r--r--src/afb-systemd.h4
-rw-r--r--src/afb-websock.c14
-rw-r--r--src/afb-ws-client.c25
-rw-r--r--src/afb-ws-json1.c11
-rw-r--r--src/afb-ws-json1.h3
-rw-r--r--src/afb-ws.c33
-rw-r--r--src/afb-ws.h4
-rw-r--r--src/afb-wsj1.c10
-rw-r--r--src/afb-wsj1.h8
-rw-r--r--src/afs-supervisor.c10
-rw-r--r--src/fdev-epoll.c97
-rw-r--r--src/fdev-epoll.h28
-rw-r--r--src/fdev-systemd.c79
-rw-r--r--src/fdev-systemd.h23
-rw-r--r--src/fdev.c158
-rw-r--r--src/fdev.h48
26 files changed, 649 insertions, 133 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4ef87853..f72d312e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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})
diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c
index 7fbe5be1..489b43b1 100644
--- a/src/afb-api-ws.c
+++ b/src/afb-api-ws.c
@@ -30,19 +30,19 @@
#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
index 00000000..943c2542
--- /dev/null
+++ b/src/afb-fdev.c
@@ -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
index 00000000..0f29a9f3
--- /dev/null
+++ b/src/afb-fdev.h
@@ -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);
diff --git a/src/afb-proto-ws.c b/src/afb-proto-ws.c
index ce7d75d3..56669e59 100644
--- a/src/afb-proto-ws.c
+++ b/src/afb-proto-ws.c
@@ -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)
diff --git a/src/afb-proto-ws.h b/src/afb-proto-ws.h
index 103e37ab..cef7eadb 100644
--- a/src/afb-proto-ws.h
+++ b/src/afb-proto-ws.h
@@ -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);
diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c
index 0049c50c..37607ee0 100644
--- a/src/afb-stub-ws.c
+++ b/src/afb-stub-ws.c
@@ -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;
diff --git a/src/afb-stub-ws.h b/src/afb-stub-ws.h
index 4e07f982..3bb56feb 100644
--- a/src/afb-stub-ws.h
+++ b/src/afb-stub-ws.h
@@ -18,13 +18,14 @@
#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);
diff --git a/src/afb-supervision.c b/src/afb-supervision.c
index f41ca18b..0f8a16bb 100644
--- a/src/afb-supervision.c
+++ b/src/afb-supervision.c
@@ -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);
diff --git a/src/afb-systemd.c b/src/afb-systemd.c
index 575d9f1b..fe47967f 100644
--- a/src/afb-systemd.c
+++ b/src/afb-systemd.c
@@ -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;
diff --git a/src/afb-systemd.h b/src/afb-systemd.h
index ae8d61b0..bf0c6a9c 100644
--- a/src/afb-systemd.h
+++ b/src/afb-systemd.h
@@ -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);
diff --git a/src/afb-websock.c b/src/afb-websock.c
index 799b2bd0..e062cf77 100644
--- a/src/afb-websock.c
+++ b/src/afb-websock.c
@@ -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);
diff --git a/src/afb-ws-client.c b/src/afb-ws-client.c
index e1d3277e..7e1a04f1 100644
--- a/src/afb-ws-client.c
+++ b/src/afb-ws-client.c
@@ -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;
}
-
-
diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c
index 0fa13dfd..68565aa2 100644
--- a/src/afb-ws-json1.c
+++ b/src/afb-ws-json1.c
@@ -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;
}
diff --git a/src/afb-ws-json1.h b/src/afb-ws-json1.h
index 96db1bc6..024dd8c0 100644
--- a/src/afb-ws-json1.h
+++ b/src/afb-ws-json1.h
@@ -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);
diff --git a/src/afb-ws.c b/src/afb-ws.c
index c48a5e24..ef73addd 100644
--- a/src/afb-ws.c
+++ b/src/afb-ws.c
@@ -26,12 +26,9 @@
#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;
}
diff --git a/src/afb-ws.h b/src/afb-ws.h
index 4b26f0b9..0af236ef 100644
--- a/src/afb-ws.h
+++ b/src/afb-ws.h
@@ -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);
diff --git a/src/afb-wsj1.c b/src/afb-wsj1.c
index be961f51..3876c322 100644
--- a/src/afb-wsj1.c
+++ b/src/afb-wsj1.c
@@ -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;
}
diff --git a/src/afb-wsj1.h b/src/afb-wsj1.h
index 7e318f6f..86c7cfdb 100644
--- a/src/afb-wsj1.h
+++ b/src/afb-wsj1.h
@@ -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'
diff --git a/src/afs-supervisor.c b/src/afs-supervisor.c
index be0cdbf5..1e92b9f3 100644
--- a/src/afs-supervisor.c
+++ b/src/afs-supervisor.c
@@ -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
index 00000000..80c037d0
--- /dev/null
+++ b/src/fdev-epoll.c
@@ -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
index 00000000..53d02e72
--- /dev/null
+++ b/src/fdev-epoll.h
@@ -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
index 00000000..0f4a03cd
--- /dev/null
+++ b/src/fdev-systemd.c
@@ -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
index 00000000..99ea5f1f
--- /dev/null
+++ b/src/fdev-systemd.h
@@ -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
index 00000000..5c31d31b
--- /dev/null
+++ b/src/fdev.c
@@ -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
index 00000000..9fbcb759
--- /dev/null
+++ b/src/fdev.h
@@ -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);