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; +}