diff --git a/Makefile.am b/Makefile.am
index 9e70d15..6475978 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,13 +20,19 @@ pkginclude_HEADERS = \
     include/igloo/ro.h \
     include/igloo/types.h \
     include/igloo/typedef.h \
+    include/igloo/interface.h \
+    include/igloo/io.h \
+    include/igloo/stdio.h \
     include/igloo/buffer.h \
     include/igloo/list.h \
     include/igloo/reportxml.h
 
 libigloo_la_SOURCES = \
     src/libigloo.c \
+    src/interface.c \
     src/ro.c \
+    src/io.c \
+    src/stdio.c \
     src/buffer.c \
     src/list.c \
     src/reportxml.c
diff --git a/include/igloo/interface.h b/include/igloo/interface.h
new file mode 100644
index 0000000..45febc3
--- /dev/null
+++ b/include/igloo/interface.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2019       Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _LIBIGLOO__INTERFACE_H_
+#define _LIBIGLOO__INTERFACE_H_
+/**
+ * @file
+ * Put a good description of this file here
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Put stuff here */
+
+#include "ro.h"
+
+/* Basic arguments that should be passed to all interface functions */
+#define igloo_INTERFACE_BASIC_ARGS igloo_ro_t self, igloo_ro_t *backend_object, void **backend_userdata
+
+/* Basic free callback.
+ * If this does not set *backend_object to igloo_RO_NULL
+ * backend_object will be freed by calling igloo_ro_unref().
+ * If this does not set *backend_userdata to NULL
+ *
+ */
+typedef int (*igloo_interface_free_t)(igloo_INTERFACE_BASIC_ARGS);
+
+#define igloo_INTERFACE_DESCRIPTION_BASE__VERSION	1
+
+typedef struct {
+    size_t base_length;
+    int base_version;
+    size_t description_length;
+    igloo_interface_free_t free;
+} igloo_interface_base_ifdesc_t;
+
+#define igloo_INTERFACE_DESCRIPTION_BASE(type, ...) \
+    .__base = { \
+        .base_length = sizeof(igloo_interface_base_ifdesc_t), \
+        .base_version = igloo_INTERFACE_DESCRIPTION_BASE__VERSION, \
+        .description_length = sizeof(type) \
+        , ## __VA_ARGS__ \
+    }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! _LIBIGLOO__INTERFACE_H_ */
diff --git a/include/igloo/io.h b/include/igloo/io.h
new file mode 100644
index 0000000..9ad54d7
--- /dev/null
+++ b/include/igloo/io.h
@@ -0,0 +1,268 @@
+/* Copyright (C) 2019       Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _LIBIGLOO__IO_H_
+#define _LIBIGLOO__IO_H_
+/**
+ * @file
+ * Put a good description of this file here
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Put stuff here */
+
+#include <igloo/config.h>
+
+#ifdef IGLOO_CTC_HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef IGLOO_CTC_HAVE_POLL
+#include <poll.h>
+#endif
+#ifdef IGLOO_CTC_HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef IGLOO_CTC_STDC_HEADERS
+#include <stdarg.h>
+#endif
+
+#include "ro.h"
+#include "interface.h"
+
+/* About thread safety:
+ * This set of functions is thread safe.
+ */
+
+igloo_RO_FORWARD_TYPE(igloo_io_t);
+
+/* Type of blocking.
+ */
+typedef enum {
+    /* Error state, used as return value only. */
+    igloo_IO_BLOCKINGMODE_ERROR = -1,
+    /* No blocking is done. This is the eqivalent of setting O_NONBLOCK on a POSIX system. */
+    igloo_IO_BLOCKINGMODE_NONE = 0,
+    /* Full blocking is done. This is the eqivalent of unsetting O_NONBLOCK on a POSIX system. */
+    igloo_IO_BLOCKINGMODE_FULL
+} libigloo_io_blockingmode_t;
+
+/* Type for operaton flags.
+ */
+#ifdef IGLOO_CTC_HAVE_STDINT_H
+typedef uint_least32_t igloo_io_opflag_t;
+#else
+typedef unsigned long int igloo_io_opflag_t;
+#endif
+
+/* No operation flags set. Usefull for variable initialization. */
+#define igloo_IO_OPFLAG_NONE            ((igloo_io_opflag_t)0x0000)
+/* Use default flags. Other flags can be set in addition. */
+#define igloo_IO_OPFLAG_DEFAULTS        ((igloo_io_opflag_t)0x8000)
+
+/* Operate on actual data. */
+#define igloo_IO_OPFLAG_DATA            ((igloo_io_opflag_t)0x0001)
+/* Operate on metadata. */
+#define igloo_IO_OPFLAG_METADATA        ((igloo_io_opflag_t)0x0002)
+/* Operate on data and metadata. */
+#define igloo_IO_OPFLAG_FULL            (igloo_IO_OPFLAG_DATAONLY|igloo_IO_OPFLAG_METADATAONLY)
+/* Instructs the operation that it should ignore the output state of the object.
+ * This may improve performance as buffer flushes may be skipped.
+ * However with this set any external software interacting with this object
+ * MUST NOT interact with the output side of this object.
+ */
+#define igloo_IO_OPFLAG_NOWRITE         ((igloo_io_opflag_t)0x0010)
+
+/* Get the referenced value */
+#define igloo_IO_OPFLAG_GET             ((igloo_io_opflag_t)0x0100)
+/* Set the referenced value */
+#define igloo_IO_OPFLAG_SET             ((igloo_io_opflag_t)0x0200)
+
+/* Advanced control functions.
+ */
+typedef enum {
+    igloo_IO_CONTROL_NONE = 0
+} igloo_io_control_t;
+
+/* Interface description */
+typedef struct {
+    igloo_interface_base_ifdesc_t __base;
+
+    ssize_t (*read)(igloo_INTERFACE_BASIC_ARGS, void *buffer, size_t len);
+    ssize_t (*write)(igloo_INTERFACE_BASIC_ARGS, const void *buffer, size_t len);
+    int (*flush)(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags);
+    int (*sync)(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags);
+    int (*set_blockingmode)(igloo_INTERFACE_BASIC_ARGS, libigloo_io_blockingmode_t mode);
+    libigloo_io_blockingmode_t (*get_blockingmode)(igloo_INTERFACE_BASIC_ARGS);
+    int (*get_fd_for_systemcall)(igloo_INTERFACE_BASIC_ARGS);
+#ifdef IGLOO_CTC_STDC_HEADERS
+    int (*control)(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags, igloo_io_control_t control, va_list ap);
+#else
+    int (*control)(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags, igloo_io_control_t control, ...);
+#endif
+} igloo_io_ifdesc_t;
+
+/* This creates a new IO handle from a interface description and state.
+ * Parameters:
+ *  ifdesc
+ *      The interface description to use.
+ *  backend_object
+ *      A object used by the backend or igloo_RO_NULL.
+ *  backend_userdata
+ *      A userdata pointer used by the backend or NULL.
+ *  name, associated
+ *      See refobject_new().
+ */
+igloo_io_t * igloo_io_new(const igloo_io_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated);
+
+/* Read data from a IO handle.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  buffer
+ *      The buffer to read to.
+ *  len
+ *      The maximum amount of bytes to read.
+ * Returns:
+ *  The actual amount of bytes read.
+ */
+ssize_t igloo_io_read(igloo_io_t *io, void *buffer, size_t len);
+/* Write data to a IO handle.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  buffer
+ *      The buffer to write from.
+ *  len
+ *      The maximum amount of bytes to write.
+ * Returns:
+ *  The actual amount of bytes written.
+ */
+ssize_t igloo_io_write(igloo_io_t *io, const void *buffer, size_t len);
+
+/* Flush internal buffers to the underlying object.
+ * This does not guarantee that all data has been written to the physical level
+ * on return. It just queues the flush.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  flags
+ *      Flags for this operation.
+ */
+int igloo_io_flush(igloo_io_t *io, igloo_io_opflag_t flags);
+/* Sync object with physical state. This is used to get the object into a state
+ * that allows passing the underlying object to other software.
+ * This may also flush internal buffers.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  flags
+ *      Flags for this operation.
+ */
+int igloo_io_sync(igloo_io_t *io, igloo_io_opflag_t flags);
+
+/* Set and get the blocking state of the object.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  mode
+ *      The new blocking mode.
+ */
+int igloo_io_set_blockingmode(igloo_io_t *io, libigloo_io_blockingmode_t mode);
+libigloo_io_blockingmode_t igloo_io_get_blockingmode(igloo_io_t *io);
+
+#ifdef IGLOO_CTC_HAVE_SYS_SELECT_H
+/* Those functions act as igloo's replacement for FD_SET(), FD_CLR(), and FD_SET() and
+ * allow the caller to use the select() system call.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  set
+ *      The fd_set to operate on.
+ *  maxfd
+ *      This parameter is updated to reflect the added handle(s)
+ *      in select()'s nfds parameter.
+ *  flags
+ *      Flags for this operation.
+ *      It may be useful to igloo_IO_OPFLAG_NOWRITE in some cases. See it's definition.
+ * Notes:
+ *  This may call igloo_io_sync(). If the object is touched between calls to igloo_io_select_set(),
+ *  select() the user MUST call igloo_io_sync() with the correct flags. It is RECOMMENDED
+ *  to avoid this, as finding the correct parameters for igloo_io_sync() might be tricky.
+ *  The object MUST NOT be touched between select() and igloo_io_select_isset().
+ */
+int igloo_io_select_set(igloo_io_t *io, fd_set *set, int *maxfd, igloo_io_opflag_t flags);
+int igloo_io_select_clear(igloo_io_t *io, fd_set *set);
+int igloo_io_select_isset(igloo_io_t *io, fd_set *set);
+#endif
+
+#ifdef IGLOO_CTC_HAVE_POLL
+/* This function initializes the pollfd structure to use this handle
+ * with the poll() system call.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  fd
+ *      The structure to initialize.
+ *  events
+ *      The events to set. libigloo uses different internal parameters based
+ *      on this parameter's value. The parameter MUST NOT be changed in the structre
+ *      after initialization.
+ * Notes:
+ *  This may call igloo_io_sync(). If the object is touched between calls to igloo_io_poll_fill(),
+ *  poll() the user MUST call igloo_io_sync() with the correct flags. It is RECOMMENDED
+ *  to avoid this, as finding the correct parameters for igloo_io_sync() might be tricky.
+ */
+int igloo_io_poll_fill(igloo_io_t *io, struct pollfd *fd, short events);
+#endif
+
+/* On a listen socket accept a new connection.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ * Returns:
+ *  The new connection or igloo_RO_NULL.
+ */
+/* TODO: Allow accept to accept()'s and accept4()'s additional parameters.
+igloo_io_t *igloo_io_accept(igloo_io_t *io);
+*/
+
+/* Advanced control interface.
+ * Parameters:
+ *  io
+ *      The IO handle to operate on.
+ *  flags
+ *      Flags for this operation.
+ *      Most controls accept igloo_IO_OPFLAG_GET and igloo_IO_OPFLAG_SET.
+ *      If both are set the value is first set as with igloo_IO_OPFLAG_SET and
+ *      the OLD value is returned as with igloo_IO_OPFLAG_GET.
+ *  control
+ *      The control command to use.
+ *  ...
+ *      Additional parameters if any.
+ *      Values are always passed as pointers.
+ */
+int igloo_io_control(igloo_io_t *io, igloo_io_opflag_t flags, igloo_io_control_t control, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! _LIBIGLOO__IO_H_ */
diff --git a/include/igloo/stdio.h b/include/igloo/stdio.h
new file mode 100644
index 0000000..cb00917
--- /dev/null
+++ b/include/igloo/stdio.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2019       Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _LIBIGLOO__STDIO_H_
+#define _LIBIGLOO__STDIO_H_
+/**
+ * @file
+ * Put a good description of this file here
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Put stuff here */
+
+#include "io.h"
+
+igloo_io_t * igloo_stdio_new_file(const char *filename, const char *mode, const char *name, igloo_ro_t associated);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! _LIBIGLOO__STDIO_H_ */
diff --git a/include/igloo/types.h b/include/igloo/types.h
index 9ea33bf..5a1e7c1 100644
--- a/include/igloo/types.h
+++ b/include/igloo/types.h
@@ -32,6 +32,7 @@ extern "C" {
 /* Included in case is not yet included */
 #include "typedef.h"
 
+typedef struct igloo_io_tag igloo_io_t;
 typedef struct igloo_buffer_tag igloo_buffer_t;
 typedef struct igloo_list_tag igloo_list_t;
 
@@ -50,6 +51,7 @@ igloo_RO_FORWARD_TYPE(igloo_ro_base_t);
 typedef union __attribute__ ((__transparent_union__)) {
     /* Those are libigloo's own types */
     igloo_RO_TYPE(igloo_ro_base_t)
+    igloo_RO_TYPE(igloo_io_t)
     igloo_RO_TYPE(igloo_buffer_t)
     igloo_RO_TYPE(igloo_list_t)
     igloo_RO_TYPE(igloo_reportxml_t)
diff --git a/src/interface.c b/src/interface.c
new file mode 100644
index 0000000..0a57aef
--- /dev/null
+++ b/src/interface.c
@@ -0,0 +1,62 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2019,      Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include <igloo/ro.h>
+#include <igloo/io.h>
+#include "private.h"
+
+void igloo_interface_base_free(igloo_ro_t self)
+{
+    igloo__interface_base_t *iface = igloo_INTERFACE_CAST(self);
+
+    if (iface->ifdesc && iface->ifdesc->free)
+        iface->ifdesc->free(igloo_INTERFACE_BASIC_CALL(self));
+
+    if (!igloo_RO_IS_NULL(iface->backend_object))
+        igloo_ro_unref(iface->backend_object);
+
+    if (iface->backend_userdata)
+        free(iface->backend_userdata);
+}
+
+igloo_ro_t igloo_interface_base_new_real(const igloo_ro_type_t *type, size_t description_length, const igloo_interface_base_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated)
+{
+    igloo_ro_t self;
+    igloo__interface_base_t *base;
+
+    if (!ifdesc)
+        return igloo_RO_NULL;
+
+    if (ifdesc->base_length != sizeof(igloo_interface_base_ifdesc_t) || ifdesc->base_version != igloo_INTERFACE_DESCRIPTION_BASE__VERSION || ifdesc->description_length != description_length)
+        return igloo_RO_NULL;
+
+    self = igloo_ro_new__raw(type, name, associated);
+    base = igloo_INTERFACE_CAST(self);
+
+    if (igloo_RO_IS_NULL(self))
+        return igloo_RO_NULL;
+
+    if (!igloo_RO_IS_NULL(backend_object)) {
+        if (igloo_ro_ref(backend_object) != 0) {
+            igloo_ro_unref(self);
+            return igloo_RO_NULL;
+        }
+    }
+
+    base->ifdesc = ifdesc;
+    base->backend_object = backend_object;
+    base->backend_userdata = backend_userdata;
+
+    return self;
+}
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..1ae625d
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,330 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2019,      Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <igloo/ro.h>
+#include <igloo/io.h>
+#include "private.h"
+
+struct igloo_io_tag {
+    igloo_interface_base(io)
+
+    /* Mutex for igloo_ro_*(). */
+    igloo_mutex_t lock;
+
+    int touched;
+#if defined(IGLOO_CTC_HAVE_SYS_SELECT_H) || defined(IGLOO_CTC_HAVE_POLL)
+    int fd;
+#endif
+};
+
+static void __free(igloo_ro_t self)
+{
+    igloo_io_t *io = igloo_RO_TO_TYPE(self, igloo_io_t);
+
+    igloo_thread_mutex_lock(&(io->lock));
+    igloo_thread_mutex_unlock(&(io->lock));
+    igloo_thread_mutex_destroy(&(io->lock));
+    igloo_interface_base_free(self);
+}
+
+igloo_RO_PUBLIC_TYPE(igloo_io_t,
+        igloo_RO_TYPEDECL_FREE(__free)
+        );
+
+
+igloo_io_t * igloo_io_new(const igloo_io_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated)
+{
+    igloo_io_t *io = igloo_interface_base_new(igloo_io_t, ifdesc, backend_object, backend_userdata, name, associated);
+    if (!io)
+        return NULL;
+
+    igloo_thread_mutex_create(&(io->lock));
+
+    io->touched = 1;
+
+    return io;
+}
+
+
+ssize_t igloo_io_read(igloo_io_t *io, void *buffer, size_t len)
+{
+    ssize_t ret = -1;
+
+    if (!io || !buffer)
+        return -1;
+
+    if (!len)
+        return 0;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    io->touched = 1;
+
+    if (io->ifdesc->read)
+        ret = io->ifdesc->read(igloo_INTERFACE_BASIC_CALL(io), buffer, len);
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+
+ssize_t igloo_io_write(igloo_io_t *io, const void *buffer, size_t len)
+{
+    ssize_t ret = -1;
+
+    if (!io || !buffer)
+        return -1;
+
+    if (!len)
+        return 0;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    io->touched = 1;
+
+    if (io->ifdesc->write)
+        ret = io->ifdesc->write(igloo_INTERFACE_BASIC_CALL(io), buffer, len);
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+
+int igloo_io_flush(igloo_io_t *io, igloo_io_opflag_t flags)
+{
+    int ret = -1;
+
+    if (!io)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    io->touched = 1;
+
+    if (io->ifdesc->flush)
+        ret = io->ifdesc->flush(igloo_INTERFACE_BASIC_CALL(io), flags);
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+
+int igloo_io_sync(igloo_io_t *io, igloo_io_opflag_t flags)
+{
+    int ret;
+
+    if (!io)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (io->ifdesc->flush)
+        io->ifdesc->flush(igloo_INTERFACE_BASIC_CALL(io), flags);
+
+    if (io->ifdesc->sync) {
+        ret = io->ifdesc->sync(igloo_INTERFACE_BASIC_CALL(io), flags);
+        if (ret != 0) {
+            igloo_thread_mutex_unlock(&(io->lock));
+            return ret;
+        }
+
+        io->touched = 0;
+
+        igloo_thread_mutex_unlock(&(io->lock));
+        return ret;
+    }
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return -1;
+}
+
+int igloo_io_set_blockingmode(igloo_io_t *io, libigloo_io_blockingmode_t mode)
+{
+    int ret = -1;
+
+    if (!io)
+        return -1;
+
+    if (mode != igloo_IO_BLOCKINGMODE_NONE && mode != igloo_IO_BLOCKINGMODE_FULL)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    io->touched = 1;
+
+    if (io->ifdesc->set_blockingmode)
+        ret = io->ifdesc->set_blockingmode(igloo_INTERFACE_BASIC_CALL(io), mode);
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+libigloo_io_blockingmode_t igloo_io_get_blockingmode(igloo_io_t *io)
+{
+    libigloo_io_blockingmode_t ret = igloo_IO_BLOCKINGMODE_ERROR;
+
+    if (!io)
+        return igloo_IO_BLOCKINGMODE_ERROR;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (io->ifdesc->get_blockingmode)
+        ret = io->ifdesc->get_blockingmode(igloo_INTERFACE_BASIC_CALL(io));
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+
+#ifdef IGLOO_CTC_HAVE_SYS_SELECT_H
+int igloo_io_select_set(igloo_io_t *io, fd_set *set, int *maxfd, igloo_io_opflag_t flags)
+{
+    int ret;
+
+    if (!io || !set || !maxfd)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (!io->ifdesc->get_fd_for_systemcall) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        return -1;
+    }
+
+    if (io->touched || !(flags & igloo_IO_OPFLAG_NOWRITE)) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        ret = igloo_io_sync(io, igloo_IO_OPFLAG_DEFAULTS|(flags & igloo_IO_OPFLAG_NOWRITE));
+
+        if (ret != 0)
+            return ret;
+
+        igloo_thread_mutex_lock(&(io->lock));
+        if (io->touched) {
+            igloo_thread_mutex_unlock(&(io->lock));
+            return -1;
+        }
+    }
+
+    io->fd = io->ifdesc->get_fd_for_systemcall(igloo_INTERFACE_BASIC_CALL(io));
+    if (io->fd < 0)
+        return -1;
+
+    FD_SET(io->fd, set);
+    if (*maxfd < io->fd)
+        *maxfd = io->fd;
+
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return 0;
+}
+
+int igloo_io_select_clear(igloo_io_t *io, fd_set *set)
+{
+    if (!io || !set)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (io->touched || io->fd < 0) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        return -1;
+    }
+
+    FD_CLR(io->fd, set);
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return 0;
+}
+
+int igloo_io_select_isset(igloo_io_t *io, fd_set *set)
+{
+    int ret = -1;
+
+    if (!io || !set)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (!io->touched && io->fd >= 0)
+        ret = FD_ISSET(io->fd, set) ? 1 : 0;
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+}
+#endif
+
+#ifdef IGLOO_CTC_HAVE_POLL
+int igloo_io_poll_fill(igloo_io_t *io, struct pollfd *fd, short events)
+{
+    static const short safe_events = POLLIN|POLLPRI
+#ifdef POLLRDHUP
+        |POLLRDHUP
+#endif
+#ifdef POLLRDNORM
+        |POLLRDNORM
+#endif
+    ;
+    int is_safe;
+    int ret;
+
+    if (!io || !fd)
+        return -1;
+
+    is_safe = !((events|safe_events) - safe_events);
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (!io->ifdesc->get_fd_for_systemcall) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        return -1;
+    }
+
+    if (io->touched || !is_safe) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        ret = igloo_io_sync(io, igloo_IO_OPFLAG_DEFAULTS|(is_safe ? 0 : igloo_IO_OPFLAG_NOWRITE));
+
+        if (ret != 0)
+            return ret;
+
+        igloo_thread_mutex_lock(&(io->lock));
+        if (io->touched) {
+            igloo_thread_mutex_unlock(&(io->lock));
+            return -1;
+        }
+    }
+
+    io->fd = io->ifdesc->get_fd_for_systemcall(igloo_INTERFACE_BASIC_CALL(io));
+    if (io->fd < 0) {
+        igloo_thread_mutex_unlock(&(io->lock));
+        return -1;
+    }
+
+    memset(fd, 0, sizeof(*fd));
+    fd->fd = io->fd;
+    fd->events = events;
+
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return 0;
+}
+#endif
+
+int igloo_io_control(igloo_io_t *io, igloo_io_opflag_t flags, igloo_io_control_t control, ...)
+{
+#ifdef IGLOO_CTC_STDC_HEADERS
+    int ret = -1;
+    va_list ap;
+
+    if (!io)
+        return -1;
+
+    igloo_thread_mutex_lock(&(io->lock));
+    if (io->ifdesc->control) {
+        va_start(ap, control);
+        ret = io->ifdesc->control(igloo_INTERFACE_BASIC_CALL(io), flags, control, ap);
+        va_end(ap);
+    }
+    igloo_thread_mutex_unlock(&(io->lock));
+
+    return ret;
+#else
+    return -1;
+#endif
+}
diff --git a/src/private.h b/src/private.h
index ed7ed5a..35d0791 100644
--- a/src/private.h
+++ b/src/private.h
@@ -19,6 +19,8 @@
 #ifndef _LIBIGLOO__PRIVATE_H_
 #define _LIBIGLOO__PRIVATE_H_
 
+#include <igloo/interface.h>
+
 /* init/shutdown of the library */
 void igloo_thread_initialize(void);
 void igloo_thread_initialize_with_log_id(int log_id);
@@ -30,5 +32,27 @@ void igloo_resolver_shutdown(void);
 void igloo_log_initialize(void);
 void igloo_log_shutdown(void);
 
+/* Basic interface */
+#define igloo_interface_base(type) \
+    /* The base object. */ \
+    igloo_ro_base_t __base; \
+    /* The interface description */ \
+    const igloo_ ## type ## _ifdesc_t *ifdesc; \
+    /* Backend object */ \
+    igloo_ro_t backend_object; \
+    /* Backend userdata */ \
+    void *backend_userdata;
+
+typedef struct {
+    igloo_interface_base(interface_base)
+} igloo__interface_base_t;
+
+void igloo_interface_base_free(igloo_ro_t self);
+
+#define igloo_INTERFACE_CAST(obj) ((igloo__interface_base_t*)igloo_RO__GETBASE(obj))
+#define igloo_INTERFACE_BASIC_CALL(obj) (obj), &(igloo_INTERFACE_CAST(obj)->backend_object), &(igloo_INTERFACE_CAST(obj)->backend_userdata)
+
+igloo_ro_t igloo_interface_base_new_real(const igloo_ro_type_t *type, size_t description_length, const igloo_interface_base_ifdesc_t *ifdesc, igloo_ro_t backend_object, void *backend_userdata, const char *name, igloo_ro_t associated);
+#define igloo_interface_base_new(type, ifdesc, backend_object, backend_userdata, name, associated) igloo_RO_TO_TYPE(igloo_interface_base_new_real(igloo_ro__type__ ## type, sizeof(*(ifdesc)), (const igloo_interface_base_ifdesc_t*)(ifdesc), (backend_object), (backend_userdata), (name), (associated)), type)
 
 #endif
diff --git a/src/stdio.c b/src/stdio.c
new file mode 100644
index 0000000..27f9ced
--- /dev/null
+++ b/src/stdio.c
@@ -0,0 +1,78 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2019,      Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <igloo/io.h>
+
+static int __free(igloo_INTERFACE_BASIC_ARGS)
+{
+    fclose(*backend_userdata);
+    *backend_userdata = NULL;
+    return 0;
+}
+
+
+static ssize_t __read(igloo_INTERFACE_BASIC_ARGS, void *buffer, size_t len)
+{
+    return fread(buffer, 1, len, *backend_userdata);
+}
+static ssize_t __write(igloo_INTERFACE_BASIC_ARGS, const void *buffer, size_t len)
+{
+    return fwrite(buffer, 1, len, *backend_userdata);
+}
+
+static int __flush(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags)
+{
+    return fflush(*backend_userdata) == 0 ? 0 : -1;
+}
+static int __sync(igloo_INTERFACE_BASIC_ARGS, igloo_io_opflag_t flags)
+{
+    return 0;
+}
+static libigloo_io_blockingmode_t __get_blockingmode(igloo_INTERFACE_BASIC_ARGS)
+{
+    return igloo_IO_BLOCKINGMODE_FULL;
+}
+static int __get_fd_for_systemcall(igloo_INTERFACE_BASIC_ARGS)
+{
+    return fileno(*backend_userdata);
+}
+
+static const igloo_io_ifdesc_t igloo_stdio_ifdesc = {
+    igloo_INTERFACE_DESCRIPTION_BASE(igloo_io_ifdesc_t,
+            .free = __free
+            ),
+    .read = __read,
+    .write = __write,
+    .flush = __flush,
+    .sync = __sync,
+    .get_blockingmode = __get_blockingmode,
+    .get_fd_for_systemcall = __get_fd_for_systemcall
+};
+
+igloo_io_t * igloo_stdio_new_file(const char *filename, const char *mode, const char *name, igloo_ro_t associated)
+{
+    FILE *file = fopen(filename, mode);
+    igloo_io_t *io;
+
+    if (!file)
+        return NULL;
+
+    io = igloo_io_new(&igloo_stdio_ifdesc, igloo_RO_NULL, file, name, associated);
+    if (!io) {
+        fclose(file);
+        return io;
+    }
+
+    return io;
+}