diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
index 8a7fb9a..a7ac95f 100644
--- a/src/shared/io-glib.c
+++ b/src/shared/io-glib.c
#include <config.h>
#endif
+#include <glib.h>
+
#include "src/shared/io.h"
+
+struct io {
+ GIOChannel *channel;
+ guint read_watch;
+ io_callback_func_t read_callback;
+ io_destroy_func_t read_destroy;
+ void *read_data;
+ guint write_watch;
+ io_callback_func_t write_callback;
+ io_destroy_func_t write_destroy;
+ void *write_data;
+};
+
+struct io *io_new(int fd)
+{
+ struct io *io;
+
+ if (fd < 0)
+ return NULL;
+
+ io = g_try_new0(struct io, 1);
+ if (!io)
+ return NULL;
+
+ io->channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_encoding(io->channel, NULL, NULL);
+ g_io_channel_set_buffered(io->channel, FALSE);
+
+ g_io_channel_set_close_on_unref(io->channel, FALSE);
+
+ io->read_watch = 0;
+ io->read_callback = NULL;
+ io->read_destroy = NULL;
+ io->read_data = NULL;
+
+ io->write_watch = 0;
+ io->write_callback = NULL;
+ io->write_destroy = NULL;
+ io->write_data = NULL;
+
+ return io;
+}
+
+void io_destroy(struct io *io)
+{
+ if (!io)
+ return;
+
+ g_io_channel_unref(io->channel);
+
+ g_free(io);
+}
+
+int io_get_fd(struct io *io)
+{
+ if (!io)
+ return -1;
+
+ return g_io_channel_unix_get_fd(io->channel);
+}
+
+bool io_set_close_on_destroy(struct io *io, bool do_close)
+{
+ if (!io)
+ return false;
+
+ if (do_close)
+ g_io_channel_set_close_on_unref(io->channel, TRUE);
+ else
+ g_io_channel_set_close_on_unref(io->channel, FALSE);
+
+ return true;
+}
+
+static void read_watch_destroy(gpointer user_data)
+{
+ struct io *io = user_data;
+
+ if (io->read_destroy)
+ io->read_destroy(io->read_data);
+
+ io->read_watch = 0;
+ io->read_callback = NULL;
+ io->read_destroy = NULL;
+ io->read_data = NULL;
+}
+
+static gboolean read_callback(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct io *io = user_data;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ return FALSE;
+
+ if (io->read_callback)
+ io->read_callback(io, io->read_data);
+
+ return TRUE;
+}
+
+bool io_set_read_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ if (!io)
+ return false;
+
+ if (io->read_watch > 0)
+ g_source_remove(io->read_watch);
+
+ io->read_watch = g_io_add_watch_full(io->channel, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ read_callback, io, read_watch_destroy);
+ if (io->read_watch == 0)
+ return false;
+
+ io->read_callback = callback;
+ io->read_destroy = destroy;
+ io->read_data = user_data;
+
+ return true;
+}
+
+static void write_watch_destroy(gpointer user_data)
+{
+ struct io *io = user_data;
+
+ if (io->write_destroy)
+ io->write_destroy(io->write_data);
+
+ io->write_watch = 0;
+ io->write_callback = NULL;
+ io->write_destroy = NULL;
+ io->write_data = NULL;
+}
+
+static gboolean write_callback(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct io *io = user_data;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ return FALSE;
+
+ if (io->write_callback)
+ io->write_callback(io, io->write_data);
+
+ return TRUE;
+}
+
+bool io_set_write_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ if (!io)
+ return false;
+
+ if (io->write_watch > 0)
+ g_source_remove(io->write_watch);
+
+ io->write_watch = g_io_add_watch_full(io->channel, G_PRIORITY_DEFAULT,
+ G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ write_callback, io, write_watch_destroy);
+ if (io->write_watch == 0)
+ return false;
+
+ io->write_callback = callback;
+ io->write_destroy = destroy;
+ io->write_data = user_data;
+
+ return true;
+}
+
+bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy)
+{
+ return false;
+}
diff --git a/src/shared/io.h b/src/shared/io.h
index 29ead9c..c48a7ab 100644
--- a/src/shared/io.h
+++ b/src/shared/io.h
*
*/
+#include <stdbool.h>
+
+typedef void (*io_destroy_func_t)(void *data);
+
+struct io;
+
+typedef void (*io_callback_func_t) (struct io *io, void *user_data);
+
+struct io *io_new(int fd);
+void io_destroy(struct io *io);
+
+int io_get_fd(struct io *io);
+bool io_set_close_on_destroy(struct io *io, bool do_close);
+
+typedef void (*io_callback_func_t)(struct io *io, void *user_data);
+
+bool io_set_read_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy);
+bool io_set_write_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy);
+bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback,
+ void *user_data, io_destroy_func_t destroy);