summaryrefslogtreecommitdiffstats
path: root/src/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/control.c')
-rw-r--r--src/control.c171
1 files changed, 103 insertions, 68 deletions
diff --git a/src/control.c b/src/control.c
index 92846511..ab75fe48 100644
--- a/src/control.c
+++ b/src/control.c
@@ -53,6 +53,8 @@
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
+static void control_handle_data(void *, unsigned short);
+
static void
control_queue_free(struct fd_list *fd)
{
@@ -84,9 +86,10 @@ control_free(struct fd_list *fd)
fd->ctx->ps_control_client = NULL;
#endif
- if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1 &&
- errno != ENOENT)
- logerr(__func__);
+ /* Remove ELE_WRITE */
+ if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ,
+ control_handle_data, fd) == -1)
+ logerr("%s: eloop_event_add", __func__);
TAILQ_REMOVE(&fd->ctx->control_fds, fd, next);
control_queue_free(fd);
free(fd);
@@ -107,9 +110,8 @@ control_delete(struct fd_list *fd)
}
static void
-control_handle_data(void *arg)
+control_handle_read(struct fd_list *fd)
{
- struct fd_list *fd = arg;
char buffer[1024];
ssize_t bytes;
@@ -145,6 +147,78 @@ control_handle_data(void *arg)
control_recvdata(fd, buffer, (size_t)bytes);
}
+static void
+control_handle_write(struct fd_list *fd)
+{
+ struct iovec iov[2];
+ int iov_len;
+ struct fd_data *data;
+
+ data = TAILQ_FIRST(&fd->queue);
+
+ if (data->data_flags & FD_SENDLEN) {
+ iov[0].iov_base = &data->data_len;
+ iov[0].iov_len = sizeof(size_t);
+ iov[1].iov_base = data->data;
+ iov[1].iov_len = data->data_len;
+ iov_len = 2;
+ } else {
+ iov[0].iov_base = data->data;
+ iov[0].iov_len = data->data_len;
+ iov_len = 1;
+ }
+
+ if (writev(fd->fd, iov, iov_len) == -1) {
+ logerr("%s: write", __func__);
+ control_delete(fd);
+ return;
+ }
+
+ TAILQ_REMOVE(&fd->queue, data, next);
+#ifdef CTL_FREE_LIST
+ TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
+#else
+ if (data->data_size != 0)
+ free(data->data);
+ free(data);
+#endif
+
+ if (TAILQ_FIRST(&fd->queue) != NULL)
+ return;
+
+ /* Remove ELE_WRITE */
+ if (fd->flags & FD_LISTEN) {
+ if (eloop_event_add(fd->ctx->eloop, fd->fd, ELE_READ,
+ control_handle_data, fd) == -1)
+ logerr("%s: eloop_event_add", __func__);
+ } else {
+ if (eloop_event_delete(fd->ctx->eloop, fd->fd) == -1)
+ logerr("%s: eloop_event_add", __func__);
+ }
+#ifdef PRIVSEP
+ if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) {
+ if (ps_ctl_sendeof(fd) == -1)
+ logerr(__func__);
+ control_free(fd);
+ }
+#endif
+}
+
+
+static void
+control_handle_data(void *arg, unsigned short events)
+{
+ struct fd_list *fd = arg;
+
+ if (events != ELE_READ && events != ELE_WRITE)
+ logerrx("%s: unexpected event 0x%04x", __func__, events);
+
+ if (events & ELE_WRITE)
+ control_handle_write(fd);
+ if (events & ELE_READ)
+ control_handle_read(fd);
+}
+
void
control_recvdata(struct fd_list *fd, char *data, size_t len)
{
@@ -221,13 +295,17 @@ control_new(struct dhcpcd_ctx *ctx, int fd, unsigned int flags)
}
static void
-control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
+control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags,
+ unsigned short events)
{
struct sockaddr_un run;
socklen_t len;
struct fd_list *l;
int fd, flags;
+ if (events != ELE_READ)
+ logerrx("%s: unexpected event 0x%04x", __func__, events);
+
len = sizeof(run);
if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1)
goto error;
@@ -249,8 +327,9 @@ control_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags)
if (l == NULL)
goto error;
- if (eloop_event_add(ctx->eloop, l->fd, control_handle_data, l) == -1)
- logerr(__func__);
+ if (eloop_event_add(ctx->eloop, l->fd, ELE_READ,
+ control_handle_data, l) == -1)
+ logerr("%s: eloop_event_add", __func__);
return;
error:
@@ -260,19 +339,19 @@ error:
}
static void
-control_handle(void *arg)
+control_handle(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
- control_handle1(ctx, ctx->control_fd, 0);
+ control_handle1(ctx, ctx->control_fd, 0, events);
}
static void
-control_handle_unpriv(void *arg)
+control_handle_unpriv(void *arg, unsigned short events)
{
struct dhcpcd_ctx *ctx = arg;
- control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV);
+ control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV, events);
}
static int
@@ -381,11 +460,15 @@ control_start(struct dhcpcd_ctx *ctx, const char *ifname, sa_family_t family)
return -1;
ctx->control_fd = fd;
- eloop_event_add(ctx->eloop, fd, control_handle, ctx);
+ if (eloop_event_add(ctx->eloop, fd, ELE_READ,
+ control_handle, ctx) == -1)
+ logerr("%s: eloop_event_add", __func__);
if ((fd = control_start1(ctx, ifname, family, S_UNPRIV)) != -1) {
ctx->control_unpriv_fd = fd;
- eloop_event_add(ctx->eloop, fd, control_handle_unpriv, ctx);
+ if (eloop_event_add(ctx->eloop, fd, ELE_READ,
+ control_handle_unpriv, ctx) == -1)
+ logerr("%s: eloop_event_add", __func__);
}
return ctx->control_fd;
}
@@ -490,62 +573,11 @@ control_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
return write(ctx->control_fd, buffer, len);
}
-static void
-control_writeone(void *arg)
-{
- struct fd_list *fd;
- struct iovec iov[2];
- int iov_len;
- struct fd_data *data;
-
- fd = arg;
- data = TAILQ_FIRST(&fd->queue);
-
- if (data->data_flags & FD_SENDLEN) {
- iov[0].iov_base = &data->data_len;
- iov[0].iov_len = sizeof(size_t);
- iov[1].iov_base = data->data;
- iov[1].iov_len = data->data_len;
- iov_len = 2;
- } else {
- iov[0].iov_base = data->data;
- iov[0].iov_len = data->data_len;
- iov_len = 1;
- }
-
- if (writev(fd->fd, iov, iov_len) == -1) {
- logerr("%s: write", __func__);
- control_delete(fd);
- return;
- }
-
- TAILQ_REMOVE(&fd->queue, data, next);
-#ifdef CTL_FREE_LIST
- TAILQ_INSERT_TAIL(&fd->free_queue, data, next);
-#else
- if (data->data_size != 0)
- free(data->data);
- free(data);
-#endif
-
- if (TAILQ_FIRST(&fd->queue) != NULL)
- return;
-
- if (eloop_event_remove_writecb(fd->ctx->eloop, fd->fd) == -1)
- logerr(__func__);
-#ifdef PRIVSEP
- if (IN_PRIVSEP_SE(fd->ctx) && !(fd->flags & FD_LISTEN)) {
- if (ps_ctl_sendeof(fd) == -1)
- logerr(__func__);
- control_free(fd);
- }
-#endif
-}
-
int
control_queue(struct fd_list *fd, void *data, size_t data_len)
{
struct fd_data *d;
+ unsigned short events;
if (data_len == 0) {
errno = EINVAL;
@@ -590,6 +622,9 @@ control_queue(struct fd_list *fd, void *data, size_t data_len)
d->data_flags = fd->flags & FD_SENDLEN;
TAILQ_INSERT_TAIL(&fd->queue, d, next);
- eloop_event_add_w(fd->ctx->eloop, fd->fd, control_writeone, fd);
- return 0;
+ events = ELE_WRITE;
+ if (fd->flags & FD_LISTEN)
+ events |= ELE_READ;
+ return eloop_event_add(fd->ctx->eloop, fd->fd, events,
+ control_handle_data, fd);
}