diff options
Diffstat (limited to 'src/client.c')
-rw-r--r-- | src/client.c | 139 |
1 files changed, 71 insertions, 68 deletions
diff --git a/src/client.c b/src/client.c index c5d7d75bc..77fd6c895 100644 --- a/src/client.c +++ b/src/client.c @@ -22,7 +22,6 @@ #include "listen.h" #include "permission.h" #include "utils.h" -#include "ioops.h" #include "main_notify.h" #include "dlist.h" #include "idle.h" @@ -78,6 +77,8 @@ struct client { size_t bufferPos; int fd; /* file descriptor; -1 if expired */ + GIOChannel *channel; + unsigned permission; /** the uid of the client process, or -1 if unknown */ @@ -134,12 +135,20 @@ void client_set_permission(struct client *client, unsigned permission) static inline void client_set_expired(struct client *client) { + if (client->channel != NULL) { + g_io_channel_unref(client->channel); + client->channel = NULL; + } + if (client->fd >= 0) { xclose(client->fd); client->fd = -1; } } +static gboolean +client_in_event(GIOChannel *source, GIOCondition condition, gpointer data); + static void client_init(struct client *client, int fd) { static unsigned int next_client_num; @@ -152,6 +161,10 @@ static void client_init(struct client *client, int fd) client->bufferPos = 0; client->fd = fd; set_nonblocking(fd); + + client->channel = g_io_channel_unix_new(client->fd); + g_io_add_watch(client->channel, G_IO_IN, client_in_event, client); + client->lastTime = time(NULL); client->cmd_list = NULL; client->deferred_send = g_queue_new(); @@ -436,91 +449,81 @@ static int client_read(struct client *client) return COMMAND_RETURN_CLOSE; } -static void client_manager_register_read_fd(fd_set * fds, int *fdmax) +static gboolean +client_out_event(G_GNUC_UNUSED GIOChannel *source, + G_GNUC_UNUSED GIOCondition condition, + gpointer data); + +static gboolean +client_in_event(G_GNUC_UNUSED GIOChannel *source, + G_GNUC_UNUSED GIOCondition condition, + gpointer data) { - struct client *client; + struct client *client = data; + int ret; - FD_ZERO(fds); - addListenSocketsToFdSet(fds, fdmax); + if (client_is_expired(client)) + return false; - list_for_each_entry(client, &clients, siblings) { - if (!client_is_expired(client) && - g_queue_is_empty(client->deferred_send)) { - FD_SET(client->fd, fds); - if (*fdmax < client->fd) - *fdmax = client->fd; - } - } -} + client->lastTime = time(NULL); -static void client_manager_register_write_fd(fd_set * fds, int *fdmax) -{ - struct client *client; + ret = client_read(client); + switch (ret) { + case COMMAND_RETURN_KILL: + client_close(client); + g_main_loop_quit(NULL); + return false; - FD_ZERO(fds); + case COMMAND_RETURN_CLOSE: + client_close(client); + return false; + } - list_for_each_entry(client, &clients, siblings) { - if (client->fd >= 0 && !client_is_expired(client) - && !g_queue_is_empty(client->deferred_send)) { - FD_SET(client->fd, fds); - if (*fdmax < client->fd) - *fdmax = client->fd; - } + if (client_is_expired(client)) { + client_close(client); + return false; } -} -int client_manager_io(void) -{ - fd_set rfds; - fd_set wfds; - fd_set efds; - struct client *client, *n; - int ret; - int fdmax = 0; + if (!g_queue_is_empty(client->deferred_send)) { + /* deferred buffers exist: schedule write */ + g_io_add_watch(client->channel, G_IO_OUT, + client_out_event, client); + return false; + } - FD_ZERO( &efds ); - client_manager_register_read_fd(&rfds, &fdmax); - client_manager_register_write_fd(&wfds, &fdmax); + /* read more */ + return true; +} - registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds); +static gboolean +client_out_event(G_GNUC_UNUSED GIOChannel *source, + G_GNUC_UNUSED GIOCondition condition, + gpointer data) +{ + struct client *client = data; - main_notify_lock(); - ret = select(fdmax + 1, &rfds, &wfds, &efds, NULL); - main_notify_unlock(); + if (client_is_expired(client)) + return false; - if (ret < 0) { - if (errno == EINTR) - return 0; + client_write_deferred(client); - g_error("select() failed: %s", strerror(errno)); + if (client_is_expired(client)) { + client_close(client); + return false; } - registered_IO_consume_fds(&ret, &rfds, &wfds, &efds); - - getConnections(&rfds); - - list_for_each_entry_safe(client, n, &clients, siblings) { - if (FD_ISSET(client->fd, &rfds)) { - ret = client_read(client); - if (ret == COMMAND_RETURN_KILL) - return COMMAND_RETURN_KILL; - if (ret == COMMAND_RETURN_CLOSE) { - client_close(client); - continue; - } - - assert(!client_is_expired(client)); + client->lastTime = time(NULL); - client->lastTime = time(NULL); - } - if (!client_is_expired(client) && - FD_ISSET(client->fd, &wfds)) { - client_write_deferred(client); - client->lastTime = time(NULL); - } + if (g_queue_is_empty(client->deferred_send)) { + /* done sending deferred buffers exist: schedule + read */ + g_io_add_watch(client->channel, G_IO_IN, + client_in_event, client); + return false; } - return 0; + /* write more */ + return true; } void client_manager_init(void) |