diff options
Diffstat (limited to 'src/control.c')
| -rw-r--r-- | src/control.c | 171 |
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); } |
