diff options
author | Andrew Shadura <andrew@shadura.me> | 2014-01-28 15:21:50 +0100 |
---|---|---|
committer | Andrew Shadura <andrew@shadura.me> | 2014-01-28 15:21:50 +0100 |
commit | 51addbcf27d7b06dae80a0e39e5f5f83e94dd8ae (patch) | |
tree | 3d00bef2d26f97257ec6f4835505cd300054a1e3 /src/libmowgli | |
parent | 1ed00f1a2893b43195f3fc747988da0bf6006797 (diff) |
Update to libmowgli 2.0.0
Diffstat (limited to 'src/libmowgli')
125 files changed, 10279 insertions, 2279 deletions
diff --git a/src/libmowgli/Makefile b/src/libmowgli/Makefile index d25902e..4cf3942 100644 --- a/src/libmowgli/Makefile +++ b/src/libmowgli/Makefile @@ -1,77 +1,19 @@ include ../../extra.mk -LIB = ${LIB_PREFIX}mowgli${LIB_SUFFIX} -LIB_MAJOR = 2 +LIB_MAJOR = 0 LIB_MINOR = 0 -DISTCLEAN = mowgli_config.h -SRCS = mowgli_alloc.c \ - mowgli_allocation_policy.c \ - mowgli_allocator.c \ - mowgli_argstack.c \ - mowgli_bitvector.c \ - mowgli_dictionary.c \ - mowgli_error_backtrace.c \ - mowgli_formatter.c \ - mowgli_global_storage.c \ - mowgli_hash.c \ - mowgli_heap.c \ - mowgli_hook.c \ - mowgli_index.c \ - mowgli_init.c \ - mowgli_ioevent.c \ - mowgli_list.c \ - mowgli_logger.c \ - mowgli_mempool.c \ - $(MOWGLI_MODULE) \ - mowgli_object.c \ - mowgli_object_class.c \ - mowgli_object_messaging.c \ - mowgli_object_metadata.c \ - mowgli_patricia.c \ - mowgli_queue.c \ - mowgli_random.c \ - mowgli_signal.c \ - mowgli_spinlock.c \ - mowgli_string.c \ +SHARED_LIB = ${LIBMOWGLI_SHARED_LIB} +STATIC_LIB = ${LIBMOWGLI_STATIC_LIB} -INCLUDES = mowgli.h \ - mowgli_alloc.h \ - mowgli_allocation_policy.h \ - mowgli_allocator.h \ - mowgli_argstack.h \ - mowgli_assert.h \ - mowgli_bitvector.h \ - mowgli_config.h \ - mowgli_dictionary.h \ - mowgli_error_backtrace.h \ - mowgli_exception.h \ - mowgli_formatter.h \ - mowgli_global_storage.h \ - mowgli_hash.h \ - mowgli_heap.h \ - mowgli_hook.h \ - mowgli_index.h \ - mowgli_init.h \ - mowgli_ioevent.h \ - mowgli_iterator.h \ - mowgli_list.h \ - mowgli_logger.h \ - mowgli_mempool.h \ - mowgli_module.h \ - mowgli_object.h \ - mowgli_object_class.h \ - mowgli_object_messaging.h \ - mowgli_object_metadata.h \ - mowgli_patricia.h \ - mowgli_queue.h \ - mowgli_random.h \ - mowgli_signal.h \ - mowgli_spinlock.h \ - mowgli_stdinc.h \ - mowgli_string.h +SUBDIRS = ${LIBMOWGLI_MODULES} platform + +INCLUDES = mowgli.h + +LIB_OBJS_EXTRA = ${LIB_OBJS} ${LIBMOWGLI_SHARED_MODULES} +OBJS_EXTRA = ${LIBMOWGLI_STATIC_MODULES} include ../../buildsys.mk -CPPFLAGS += ${LIB_CPPFLAGS} -I. -I.. -DMOWGLI_CORE -CFLAGS += ${LIB_CFLAGS} +LIBS += ${PTHREAD_LIBS} +CPPFLAGS += -I. -I../.. -DMOWGLI_CORE diff --git a/src/libmowgli/base/Makefile b/src/libmowgli/base/Makefile new file mode 100644 index 0000000..3d6b0e7 --- /dev/null +++ b/src/libmowgli/base/Makefile @@ -0,0 +1,29 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_BASE} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_BASE} + +SRCS = argstack.c \ + bitvector.c \ + formatter.c \ + hash.c \ + hook.c \ + memslice.c \ + random.c \ + mowgli_signal.c + +INCLUDES = argstack.h \ + bitvector.h \ + formatter.h \ + hash.h \ + hook.h \ + memslice.h \ + random.h \ + mowgli_signal.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/base + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/mowgli_argstack.c b/src/libmowgli/base/argstack.c index 0ad5c91..ea67da2 100644 --- a/src/libmowgli/mowgli_argstack.c +++ b/src/libmowgli/base/argstack.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_argstack.c: Argument stacks. + * argstack.c: Argument stacks. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -52,7 +52,7 @@ static void mowgli_argstack_destroy(void *vptr) * Side Effects: * - the mowgli_argstack_t object class is registered. */ -void mowgli_argstack_init(void) +void mowgli_argstack_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_argstack_t", mowgli_argstack_destroy, FALSE); } diff --git a/src/libmowgli/mowgli_argstack.h b/src/libmowgli/base/argstack.h index 8e7428c..adf68c2 100644 --- a/src/libmowgli/mowgli_argstack.h +++ b/src/libmowgli/base/argstack.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_argstack.h: Argument stacks. + * argstack.h: Argument stacks. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -46,9 +46,9 @@ typedef struct { mowgli_list_t stack; } mowgli_argstack_t; +extern void mowgli_argstack_bootstrap(void); extern mowgli_argstack_t *mowgli_argstack_create(const char *descstr, ...); extern mowgli_argstack_t *mowgli_argstack_create_from_va_list(const char *descstr, va_list va); -extern void mowgli_argstack_init(void); extern const char *mowgli_argstack_pop_string(mowgli_argstack_t *); extern int mowgli_argstack_pop_numeric(mowgli_argstack_t *); extern mowgli_boolean_t mowgli_argstack_pop_boolean(mowgli_argstack_t *); diff --git a/src/libmowgli/mowgli_bitvector.c b/src/libmowgli/base/bitvector.c index 8186c16..b70df55 100644 --- a/src/libmowgli/mowgli_bitvector.c +++ b/src/libmowgli/base/bitvector.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_bitvector.c: Bitvectors. + * bitvector.c: Bitvectors. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -39,7 +39,7 @@ static mowgli_object_class_t klass; * Side Effects: * - the mowgli_bitvector_t object class is registered. */ -void mowgli_bitvector_init(void) +void mowgli_bitvector_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_bitvector_t", mowgli_free, FALSE); } diff --git a/src/libmowgli/mowgli_bitvector.h b/src/libmowgli/base/bitvector.h index 195d8d9..592ba59 100644 --- a/src/libmowgli/mowgli_bitvector.h +++ b/src/libmowgli/base/bitvector.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_bitvector.h: Bitvectors. + * bitvector.h: Bitvectors. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -30,7 +30,7 @@ typedef struct { unsigned int *vector; } mowgli_bitvector_t; -extern void mowgli_bitvector_init(void); +extern void mowgli_bitvector_bootstrap(void); extern mowgli_bitvector_t *mowgli_bitvector_create(int bits); extern void mowgli_bitvector_set(mowgli_bitvector_t *bv, int slot, mowgli_boolean_t val); extern mowgli_boolean_t mowgli_bitvector_get(mowgli_bitvector_t *bv, int slot); diff --git a/src/libmowgli/mowgli_formatter.c b/src/libmowgli/base/formatter.c index b6aa1cc..21d9e46 100644 --- a/src/libmowgli/mowgli_formatter.c +++ b/src/libmowgli/base/formatter.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_formatter.c: Reusable formatting. + * formatter.c: Reusable formatting. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_formatter.h b/src/libmowgli/base/formatter.h index 2631ad6..2cfa1ce 100644 --- a/src/libmowgli/mowgli_formatter.h +++ b/src/libmowgli/base/formatter.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_formatter.h: Reusable formatting. + * formatter.h: Reusable formatting. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_hash.c b/src/libmowgli/base/hash.c index 3f331e4..7d70d8c 100644 --- a/src/libmowgli/mowgli_hash.c +++ b/src/libmowgli/base/hash.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_hash.c: FNV-1 hashing implementation. + * hash.c: FNV-1 hashing implementation. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -33,7 +33,11 @@ int mowgli_fnv_hash_string(const char *p) unsigned int hval = HASHINIT; if (htoast == 0) - htoast = rand(); + { + mowgli_random_t *r = mowgli_random_create(); + htoast = mowgli_random_int(r); + mowgli_object_unref(r); + } if (!p) return (0); @@ -52,7 +56,11 @@ int mowgli_fnv_hash(unsigned int *p) unsigned int hval = HASHINIT; if (htoast == 0) - htoast = rand(); + { + mowgli_random_t *r = mowgli_random_create(); + htoast = mowgli_random_int(r); + mowgli_object_unref(r); + } if (!p) return (0); diff --git a/src/libmowgli/mowgli_hash.h b/src/libmowgli/base/hash.h index e8e04cd..1848174 100644 --- a/src/libmowgli/mowgli_hash.h +++ b/src/libmowgli/base/hash.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_hash.h: FNV-1 hashing implementation. + * hash.h: FNV-1 hashing implementation. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_hook.c b/src/libmowgli/base/hook.c index 8527a6b..0af9660 100644 --- a/src/libmowgli/mowgli_hook.c +++ b/src/libmowgli/base/hook.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_hook.c: Hooks. + * hook.c: Hooks. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007 Giacomo Lozito <james -at- develia.org> @@ -37,7 +37,7 @@ static void _hook_key_canon(char *str) } void -mowgli_hook_init(void) +mowgli_hook_bootstrap(void) { mowgli_hooks = mowgli_patricia_create(_hook_key_canon); mowgli_hook_item_heap = mowgli_heap_create(sizeof(mowgli_hook_item_t), 64, BH_NOW); @@ -58,7 +58,7 @@ mowgli_hook_register(const char *name) return_if_fail((hook = mowgli_hook_find(name)) == NULL); hook = mowgli_alloc(sizeof(mowgli_hook_t)); - hook->name = strdup(name); + hook->name = mowgli_strdup(name); mowgli_patricia_add(mowgli_hooks, hook->name, hook); } diff --git a/src/libmowgli/mowgli_hook.h b/src/libmowgli/base/hook.h index 2e79086..366e123 100644 --- a/src/libmowgli/mowgli_hook.h +++ b/src/libmowgli/base/hook.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_hook.h: Hooks. + * hook.h: Hooks. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007 Giacomo Lozito <james -at- develia.org> @@ -38,7 +38,7 @@ typedef struct { mowgli_list_t items; } mowgli_hook_t; -extern void mowgli_hook_init(void); +extern void mowgli_hook_bootstrap(void); extern void mowgli_hook_register(const char *name); extern int mowgli_hook_associate(const char *name, mowgli_hook_function_t func, void * user_data); extern int mowgli_hook_dissociate(const char *name, mowgli_hook_function_t func); diff --git a/src/libmowgli/base/memslice.c b/src/libmowgli/base/memslice.c new file mode 100644 index 0000000..a271821 --- /dev/null +++ b/src/libmowgli/base/memslice.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_list_t allocator_list; +static mowgli_heap_t *allocator_heap; + +/* + * Our slice allocation engine. + */ +typedef struct { + size_t size; + + mowgli_heap_t *heap; + mowgli_node_t node; +} slice_alloc_t; + +/* + * Allocation tag. + */ +typedef struct { + slice_alloc_t *owner; +} slice_tag_t; + +/* + * Given a size_t, determine the closest power-of-two, which is larger. + */ +static inline size_t +nexthigher(size_t k) +{ + size_t i; + + k--; + for (i = 1; i < sizeof(k) * 8; i <<= 1) + k |= k >> i; + + return k + 1; +} + +/* + * Set up an allocator. + */ +static inline slice_alloc_t * +create_allocator(size_t k) +{ + slice_alloc_t *a; + + a = mowgli_heap_alloc(allocator_heap); + mowgli_node_add(a, &a->node, &allocator_list); + + a->size = k; + a->heap = mowgli_heap_create(k, 16, BH_LAZY); + + return a; +} + +/* + * Find an allocator which fits the requested allocation size. + */ +static inline slice_alloc_t * +find_or_create_allocator(size_t i) +{ + size_t k; + mowgli_node_t *n; + + k = nexthigher(i); + MOWGLI_ITER_FOREACH(n, allocator_list.head) + { + slice_alloc_t *a = n->data; + + if (a->size == k) + return a; + } + + return create_allocator(k); +} + +/* + * Allocate a slice of memory. + */ +static void * +memslice_alloc(size_t i) +{ + void *ptr; + slice_alloc_t *alloc; + size_t adj_size; + + adj_size = i + sizeof(slice_tag_t); + alloc = find_or_create_allocator(adj_size); + + ptr = mowgli_heap_alloc(alloc->heap); + ((slice_tag_t *) ptr)->owner = alloc; + + return ptr + sizeof(slice_tag_t); +} + +/* + * Free a slice of memory. + */ +static void +memslice_free(void *ptr) +{ + slice_tag_t *tag; + + return_if_fail(ptr != NULL); + + tag = ptr - sizeof(slice_tag_t); + mowgli_heap_free(tag->owner->heap, tag); +} + +/* + * Initialize memslice. + */ +static mowgli_allocation_policy_t *memslice = NULL; + +void +mowgli_memslice_bootstrap(void) +{ + allocator_heap = mowgli_heap_create(sizeof(slice_alloc_t), 16, BH_NOW); + + memslice = mowgli_allocation_policy_create("memslice", memslice_alloc, memslice_free); +} + +mowgli_allocation_policy_t * +mowgli_memslice_get_policy(void) +{ + return memslice; +} diff --git a/src/libmowgli/base/memslice.h b/src/libmowgli/base/memslice.h new file mode 100644 index 0000000..9d6e842 --- /dev/null +++ b/src/libmowgli/base/memslice.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_MEMSLICE_H__ +#define __MOWGLI_MEMSLICE_H__ + +void mowgli_memslice_bootstrap(void); +mowgli_allocation_policy_t *mowgli_memslice_get_policy(void); + +#endif diff --git a/src/libmowgli/mowgli_signal.c b/src/libmowgli/base/mowgli_signal.c index 3fdd708..208ce37 100644 --- a/src/libmowgli/mowgli_signal.c +++ b/src/libmowgli/base/mowgli_signal.c @@ -23,6 +23,7 @@ #ifndef _WIN32 +#include <signal.h> #include "mowgli.h" static mowgli_signal_handler_t diff --git a/src/libmowgli/mowgli_signal.h b/src/libmowgli/base/mowgli_signal.h index cc3db11..b194d8d 100644 --- a/src/libmowgli/mowgli_signal.h +++ b/src/libmowgli/base/mowgli_signal.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_signal.c: Safe signal handling. + * mowgli_signal.h: Safe signal handling. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_random.c b/src/libmowgli/base/random.c index cd6d03e..b316033 100644 --- a/src/libmowgli/mowgli_random.c +++ b/src/libmowgli/base/random.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_random.c: Portable mersinne-twister based psuedo-random number generator. + * random.c: Portable mersinne-twister based psuedo-random number generator. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Algorithm copyright (c) 1999-2007 Takuji Nishimura and Makoto Matsumoto @@ -42,7 +42,7 @@ struct mowgli_random_ static mowgli_object_class_t klass; /* initialization */ -void mowgli_random_init(void) +void mowgli_random_bootstrap(void) { mowgli_object_class_init(&klass, "mowgli_random_t", NULL, FALSE); } @@ -109,8 +109,8 @@ unsigned int mowgli_random_int(mowgli_random_t *self) /* tempering */ y ^= (y >> 11); - y ^= (y >> 7) & 0x9d2c5680U; - y ^= (y >> 15) & 0xefc60000U; + y ^= (y << 7) & 0x9d2c5680U; + y ^= (y << 15) & 0xefc60000U; y ^= (y >> 18); return y; @@ -118,7 +118,7 @@ unsigned int mowgli_random_int(mowgli_random_t *self) int mowgli_random_int_ranged(mowgli_random_t *self, int begin, int end) { - int dist = end - begin; + unsigned int dist = end - begin; unsigned int max, ret; if (dist <= 0x80000000U) diff --git a/src/libmowgli/mowgli_random.h b/src/libmowgli/base/random.h index 6fb0e61..ea53dd7 100644 --- a/src/libmowgli/mowgli_random.h +++ b/src/libmowgli/base/random.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_random.h: Portable mersinne-twister based psuedo-random number generator. + * random.h: Portable mersinne-twister based psuedo-random number generator. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -29,7 +29,7 @@ struct mowgli_random_; typedef struct mowgli_random_ mowgli_random_t; /* object class initialization. */ -extern void mowgli_random_init(void); +extern void mowgli_random_bootstrap(void); /* construction and destruction. */ extern mowgli_random_t *mowgli_random_create(void); diff --git a/src/libmowgli/container/Makefile b/src/libmowgli/container/Makefile new file mode 100644 index 0000000..1c97ee9 --- /dev/null +++ b/src/libmowgli/container/Makefile @@ -0,0 +1,23 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_CONTAINER} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_CONTAINER} + +SRCS = dictionary.c \ + list.c \ + queue.c \ + index.c \ + patricia.c + +INCLUDES = dictionary.h \ + list.h \ + queue.h \ + index.h \ + patricia.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/container + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/mowgli_dictionary.c b/src/libmowgli/container/dictionary.c index abcb2f9..22445d7 100644 --- a/src/libmowgli/mowgli_dictionary.c +++ b/src/libmowgli/container/dictionary.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_dictionary.c: Dictionary-based information storage. + * dictionary.c: Dictionary-based information storage. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007 Jilles Tjoelker <jilles -at- stack.nl> @@ -32,20 +32,9 @@ struct mowgli_dictionary_ mowgli_dictionary_elem_t *root, *head, *tail; unsigned int count; char *id; - mowgli_boolean_t dirty; + bool dirty; }; -static void warn_deprecated (void) -{ - static char warned = 0; - if (warned) - return; - - printf("mowgli_dictionary is deprecated and pending removal in Mowgli 1.0 " - "series.\nPlease use mowgli_patricia instead.\n"); - warned = 1; -} - /* * mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) * @@ -70,7 +59,6 @@ mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_ if (!elem_heap) elem_heap = mowgli_heap_create(sizeof(mowgli_dictionary_elem_t), 1024, BH_NOW); - warn_deprecated(); return dtree; } @@ -102,7 +90,6 @@ mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, if (!elem_heap) elem_heap = mowgli_heap_create(sizeof(mowgli_dictionary_elem_t), 1024, BH_NOW); - warn_deprecated(); return dtree; } @@ -156,7 +143,7 @@ mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) /* * mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, - * const char *key) + * const void *key) * * Gets a linear index number for key. * @@ -171,7 +158,7 @@ mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) * - rebuilds the linear index if the tree is marked as dirty. */ int -mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) +mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const void *key) { mowgli_dictionary_elem_t *elem; @@ -192,14 +179,14 @@ mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) for (delem = dict->head, i = 0; delem != NULL; delem = delem->next, i++) delem->position = i; - dict->dirty = FALSE; + dict->dirty = false; } return elem->position; } /* - * mowgli_dictionary_retune(mowgli_dictionary_t *dict, const char *key) + * mowgli_dictionary_retune(mowgli_dictionary_t *dict, const void *key) * * Retunes the tree, self-optimizing for the element which belongs to key. * @@ -247,10 +234,10 @@ mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) * - a new root node is nominated. */ void -mowgli_dictionary_retune(mowgli_dictionary_t *dict, const char *key) +mowgli_dictionary_retune(mowgli_dictionary_t *dict, const void *key) { mowgli_dictionary_elem_t n, *tn, *left, *right, *node; - int ret; + ptrdiff_t ret; return_if_fail(dict != NULL); @@ -352,7 +339,7 @@ mowgli_dictionary_link(mowgli_dictionary_t *dict, return_if_fail(dict != NULL); return_if_fail(delem != NULL); - dict->dirty = TRUE; + dict->dirty = true; dict->count++; @@ -430,7 +417,7 @@ mowgli_dictionary_unlink_root(mowgli_dictionary_t *dict) { mowgli_dictionary_elem_t *delem, *nextnode, *parentofnext; - dict->dirty = TRUE; + dict->dirty = true; delem = dict->root; if (delem == NULL) @@ -515,7 +502,6 @@ void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, if (destroy_cb != NULL) (*destroy_cb)(n, privdata); - mowgli_free(n->key); mowgli_heap_free(elem_heap, n); } @@ -701,7 +687,7 @@ void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, } /* - * mowgli_dictionary_find(mowgli_dictionary_t *dtree, const char *key) + * mowgli_dictionary_find(mowgli_dictionary_t *dtree, const void *key) * * Looks up a DTree node by name. * @@ -716,7 +702,7 @@ void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, * Side Effects: * - none */ -mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, const char *key) +mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, const void *key) { return_val_if_fail(dict != NULL, NULL); return_val_if_fail(key != NULL, NULL); @@ -731,7 +717,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, cons } /* - * mowgli_dictionary_add(mowgli_dictionary_t *dtree, const char *key, void *data) + * mowgli_dictionary_add(mowgli_dictionary_t *dtree, const void *key, void *data) * * Creates a new DTree node and binds data to it. * @@ -747,7 +733,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dict, cons * Side Effects: * - data is inserted into the DTree. */ -mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const char *key, void *data) +mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const void *key, void *data) { mowgli_dictionary_elem_t *delem; @@ -757,7 +743,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const return_val_if_fail(mowgli_dictionary_find(dict, key) == NULL, NULL); delem = mowgli_heap_alloc(elem_heap); - delem->key = strdup(key); + delem->key = key; delem->data = data; if (delem->key == NULL) @@ -773,7 +759,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const } /* - * mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) + * mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) * * Deletes data from a dictionary tree. * @@ -791,7 +777,7 @@ mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dict, const * Notes: * - the returned data needs to be mowgli_freed/released manually! */ -void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) +void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key) { mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); void *data; @@ -801,7 +787,6 @@ void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) data = delem->data; - mowgli_free(delem->key); mowgli_dictionary_unlink_root(dtree); mowgli_heap_free(elem_heap, delem); @@ -809,7 +794,7 @@ void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) } /* - * mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) + * mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key) * * Retrieves data from a dictionary. * @@ -824,7 +809,7 @@ void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) * Side Effects: * - none */ -void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) +void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key) { mowgli_dictionary_elem_t *delem = mowgli_dictionary_find(dtree, key); diff --git a/src/libmowgli/mowgli_dictionary.h b/src/libmowgli/container/dictionary.h index 884cde4..3c2f4e5 100644 --- a/src/libmowgli/mowgli_dictionary.h +++ b/src/libmowgli/container/dictionary.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_dictionary.h: Dictionary-based storage. + * dictionary.h: Dictionary-based storage. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007 Jilles Tjoelker <jilles -at- stack.nl> @@ -31,13 +31,13 @@ typedef struct mowgli_dictionary_ mowgli_dictionary_t; typedef struct mowgli_dictionary_elem_ mowgli_dictionary_elem_t; -typedef int (*mowgli_dictionary_comparator_func_t)(const char *a, const char *b); +typedef ptrdiff_t (*mowgli_dictionary_comparator_func_t)(const void *a, const void *b); struct mowgli_dictionary_elem_ { mowgli_dictionary_elem_t *left, *right, *prev, *next; void *data; - char *key; + const void *key; int position; }; @@ -63,32 +63,32 @@ typedef struct mowgli_dictionary_iteration_state_ mowgli_dictionary_iteration_st * compare_cb is the comparison function, typically strcmp, strcasecmp or * irccasecmp. */ -extern mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; +extern mowgli_dictionary_t *mowgli_dictionary_create(mowgli_dictionary_comparator_func_t compare_cb); /* * mowgli_dictionary_create_named() creates a new dictionary tree which has a name. * name is the name, compare_cb is the comparator. */ -extern mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; +extern mowgli_dictionary_t *mowgli_dictionary_create_named(const char *name, mowgli_dictionary_comparator_func_t compare_cb); /* * mowgli_dictionary_set_comparator_func() resets the comparator used for lookups and * insertions in the DTree structure. */ extern void mowgli_dictionary_set_comparator_func(mowgli_dictionary_t *dict, - mowgli_dictionary_comparator_func_t compare_cb) MOWGLI_DEPRECATED; + mowgli_dictionary_comparator_func_t compare_cb); /* * mowgli_dictionary_get_comparator_func() returns the comparator used for lookups and * insertions in the DTree structure. */ -extern mowgli_dictionary_comparator_func_t mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict) MOWGLI_DEPRECATED; +extern mowgli_dictionary_comparator_func_t mowgli_dictionary_get_comparator_func(mowgli_dictionary_t *dict); /* * mowgli_dictionary_get_linear_index() returns the linear index of an object in the * DTree structure. */ -extern int mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const char *key) MOWGLI_DEPRECATED; +extern int mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const void *key); /* * mowgli_dictionary_destroy() destroys all entries in a dtree, and also optionally calls @@ -96,7 +96,7 @@ extern int mowgli_dictionary_get_linear_index(mowgli_dictionary_t *dict, const c */ extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, void (*destroy_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) MOWGLI_DEPRECATED; + void *privdata); /* * mowgli_dictionary_foreach() iterates all entries in a dtree, and also optionally calls @@ -106,7 +106,7 @@ extern void mowgli_dictionary_destroy(mowgli_dictionary_t *dtree, */ extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, int (*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) MOWGLI_DEPRECATED; + void *privdata); /* * mowgli_dictionary_search() iterates all entries in a dtree, and also optionally calls @@ -117,7 +117,7 @@ extern void mowgli_dictionary_foreach(mowgli_dictionary_t *dtree, */ extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, void *(*foreach_cb)(mowgli_dictionary_elem_t *delem, void *privdata), - void *privdata) MOWGLI_DEPRECATED; + void *privdata); /* * mowgli_dictionary_foreach_start() begins an iteration over all items @@ -126,41 +126,41 @@ extern void *mowgli_dictionary_search(mowgli_dictionary_t *dtree, * of the iteration (but not any other element). */ extern void mowgli_dictionary_foreach_start(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_foreach_cur() returns the current element of the iteration, * or NULL if there are no more elements. */ extern void *mowgli_dictionary_foreach_cur(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_foreach_next() moves to the next element. */ extern void mowgli_dictionary_foreach_next(mowgli_dictionary_t *dtree, - mowgli_dictionary_iteration_state_t *state) MOWGLI_DEPRECATED; + mowgli_dictionary_iteration_state_t *state); /* * mowgli_dictionary_add() adds a key->value entry to the dictionary tree. */ -extern mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dtree, const char *key, void *data) MOWGLI_DEPRECATED; +extern mowgli_dictionary_elem_t *mowgli_dictionary_add(mowgli_dictionary_t *dtree, const void *key, void *data); /* * mowgli_dictionary_find() returns a mowgli_dictionary_elem_t container from a dtree for key 'key'. */ -extern mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; +extern mowgli_dictionary_elem_t *mowgli_dictionary_find(mowgli_dictionary_t *dtree, const void *key); /* * mowgli_dictionary_find() returns data from a dtree for key 'key'. */ -extern void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; +extern void *mowgli_dictionary_retrieve(mowgli_dictionary_t *dtree, const void *key); /* * mowgli_dictionary_delete() deletes a key->value entry from the dictionary tree. */ -extern void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const char *key) MOWGLI_DEPRECATED; +extern void *mowgli_dictionary_delete(mowgli_dictionary_t *dtree, const void *key); -void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata) MOWGLI_DEPRECATED; +void mowgli_dictionary_stats(mowgli_dictionary_t *dict, void (*cb)(const char *line, void *privdata), void *privdata); #endif diff --git a/src/libmowgli/mowgli_index.c b/src/libmowgli/container/index.c index b96b45e..81776f5 100644 --- a/src/libmowgli/mowgli_index.c +++ b/src/libmowgli/container/index.c @@ -20,7 +20,7 @@ #include <stdlib.h> #include <string.h> -#include <mowgli.h> +#include "mowgli.h" struct mowgli_index_ { @@ -63,16 +63,28 @@ int mowgli_index_count (mowgli_index_t * index) void mowgli_index_allocate (mowgli_index_t * index, int size) { + size_t oldsize; + void *new_ptr; + if (size <= index->size) return; if (! index->size) index->size = 64; + oldsize = index->size; while (size > index->size) index->size <<= 1; - index->data = realloc (index->data, sizeof (void *) * index->size); + new_ptr = mowgli_alloc_array(sizeof (void *), index->size); + + if (index->data != NULL) + { + memcpy(new_ptr, index->data, oldsize); + mowgli_free(index->data); + } + + index->data = new_ptr; } void mowgli_index_set (mowgli_index_t * index, int at, void * value) diff --git a/src/libmowgli/mowgli_index.h b/src/libmowgli/container/index.h index 85e9e72..85e9e72 100644 --- a/src/libmowgli/mowgli_index.h +++ b/src/libmowgli/container/index.h diff --git a/src/libmowgli/mowgli_list.c b/src/libmowgli/container/list.c index 0e33103..6283910 100644 --- a/src/libmowgli/mowgli_list.c +++ b/src/libmowgli/container/list.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_list.c: Linked lists. + * list.c: Linked lists. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -26,7 +26,7 @@ static mowgli_heap_t *mowgli_node_heap; static mowgli_heap_t *mowgli_list_heap; -void mowgli_node_init(void) +void mowgli_node_bootstrap(void) { mowgli_node_heap = mowgli_heap_create(sizeof(mowgli_node_t), 1024, BH_NOW); mowgli_list_heap = mowgli_heap_create(sizeof(mowgli_list_t), 64, BH_NOW); @@ -141,7 +141,10 @@ void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowg n->prev = before->prev; n->next = before; before->prev = n; - n->prev->next = n; + + if (n->prev != NULL) + n->prev->next = n; + l->count++; } } @@ -166,16 +169,13 @@ void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgl } /* retrieves a node at `position` position. */ -mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, int pos) +mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, size_t pos) { - int iter; + size_t iter; mowgli_node_t *n; return_val_if_fail(l != NULL, NULL); - if (pos < 0) - return NULL; - /* locate the proper position. */ if (pos < MOWGLI_LIST_LENGTH(l) / 2) for (iter = 0, n = l->head; iter != pos && n != NULL; iter++, n = n->next); @@ -187,7 +187,7 @@ mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, int pos) } /* returns the data from node at `position` position, or NULL. */ -void *mowgli_node_nth_data(mowgli_list_t *l, int pos) +void *mowgli_node_nth_data(mowgli_list_t *l, size_t pos) { mowgli_node_t *n; @@ -202,7 +202,7 @@ void *mowgli_node_nth_data(mowgli_list_t *l, int pos) } /* inserts a node at `position` position. */ -void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, int pos) +void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, size_t pos) { mowgli_node_t *tn; @@ -216,9 +216,9 @@ void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, int pos) } /* retrieves the index position of a node in a list. */ -int mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) +ssize_t mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) { - int iter; + ssize_t iter; mowgli_node_t *tn; return_val_if_fail(n != NULL, -1); @@ -227,7 +227,7 @@ int mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l) /* locate the proper position. */ for (iter = 0, tn = l->head; tn != n && tn != NULL; iter++, tn = tn->next); - return iter < MOWGLI_LIST_LENGTH(l) ? iter : -1; + return iter < (ssize_t) MOWGLI_LIST_LENGTH(l) ? iter : -1; } /* deletes a link between a node and a list. */ @@ -319,8 +319,12 @@ void mowgli_list_concat(mowgli_list_t *l, mowgli_list_t *l2) return_if_fail(l != NULL); return_if_fail(l2 != NULL); - l->tail->next = l2->head; - l->tail->next->prev = l->tail; + if (l->tail != NULL) + l->tail->next = l2->head; + + if (l->tail->next != NULL) + l->tail->next->prev = l->tail; + l->tail = l2->tail; l->count += l2->count; diff --git a/src/libmowgli/mowgli_list.h b/src/libmowgli/container/list.h index 2699686..19905b4 100644 --- a/src/libmowgli/mowgli_list.h +++ b/src/libmowgli/container/list.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_list.c: Linked lists. + * list.h: Linked lists. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -50,20 +50,20 @@ struct mowgli_list_ size_t count; /* how many entries in the list */ }; -extern void mowgli_node_init(void); +extern void mowgli_node_bootstrap(void); extern mowgli_node_t *mowgli_node_create(void); extern void mowgli_node_free(mowgli_node_t *n); extern void mowgli_node_add(void *data, mowgli_node_t *n, mowgli_list_t *l); extern void mowgli_node_add_head(void *data, mowgli_node_t *n, mowgli_list_t *l); extern void mowgli_node_add_before(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before); extern void mowgli_node_add_after(void *data, mowgli_node_t *n, mowgli_list_t *l, mowgli_node_t *before); -extern void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, int position); -extern int mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l); +extern void mowgli_node_insert(void *data, mowgli_node_t *n, mowgli_list_t *l, size_t position); +extern ssize_t mowgli_node_index(mowgli_node_t *n, mowgli_list_t *l); extern void mowgli_node_delete(mowgli_node_t *n, mowgli_list_t *l); extern mowgli_node_t *mowgli_node_find(void *data, mowgli_list_t *l); extern void mowgli_node_move(mowgli_node_t *m, mowgli_list_t *oldlist, mowgli_list_t *newlist); -extern mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, int pos); -extern void *mowgli_node_nth_data(mowgli_list_t *l, int pos); +extern mowgli_node_t *mowgli_node_nth(mowgli_list_t *l, size_t pos); +extern void *mowgli_node_nth_data(mowgli_list_t *l, size_t pos); typedef int (*mowgli_list_comparator_t)(mowgli_node_t *n, mowgli_node_t *n2, void *opaque); diff --git a/src/libmowgli/mowgli_patricia.c b/src/libmowgli/container/patricia.c index cf9af5c..b530d33 100644 --- a/src/libmowgli/mowgli_patricia.c +++ b/src/libmowgli/container/patricia.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_patricia.c: Dictionary-based information storage. + * patricia.c: Dictionary-based information storage. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007-2010 Jilles Tjoelker <jilles -at- stack.nl> @@ -193,7 +193,7 @@ mowgli_patricia_t *mowgli_patricia_create_named(const char *name, mowgli_patricia_t *dtree = (mowgli_patricia_t *) mowgli_alloc(sizeof(mowgli_patricia_t)); dtree->canonize_cb = canonize_cb; - dtree->id = strdup(name); + dtree->id = mowgli_strdup(name); if (!leaf_heap) leaf_heap = mowgli_heap_create(sizeof(struct patricia_leaf), 1024, BH_NOW); @@ -206,6 +206,31 @@ mowgli_patricia_t *mowgli_patricia_create_named(const char *name, } /* + * mowgli_patricia_shutdown(void) + * + * Clean up after patricia to ensure all memory is released as soon as + * possible (destroys both heaps). + * + * Inputs: + * - nothing + * + * Outputs: + * - nothing + * + * Side Effects: + * - patricia's internal heaps are destroyed and deallocated + */ +void mowgli_patricia_shutdown(void) +{ + if(leaf_heap) + mowgli_heap_destroy(leaf_heap); + if(node_heap) + mowgli_heap_destroy(node_heap); + + return; +} + +/* * mowgli_patricia_destroy(mowgli_patricia_t *dtree, * void (*destroy_cb)(const char *key, void *data, void *privdata), * void *privdata); @@ -571,9 +596,9 @@ struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const c ckey = key; else { - if (keylen >= sizeof ckey_store) + if (keylen >= (int) sizeof(ckey_store)) { - ckey_buf = strdup(key); + ckey_buf = mowgli_strdup(key); dict->canonize_cb(ckey_buf); ckey = ckey_buf; } @@ -599,7 +624,7 @@ struct patricia_leaf *mowgli_patricia_elem_find(mowgli_patricia_t *dict, const c delem = NULL; if (ckey_buf != NULL) - free(ckey_buf); + mowgli_free(ckey_buf); return &delem->leaf; } @@ -634,7 +659,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch return_val_if_fail(data != NULL, FALSE); keylen = strlen(key); - ckey = strdup(key); + ckey = mowgli_strdup(key); if (ckey == NULL) { mowgli_log("major WTF: ckey is NULL, not adding node."); @@ -659,7 +684,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch if (delem != NULL && !strcmp(delem->leaf.key, ckey)) { mowgli_log("Key is already in dict, ignoring duplicate"); - free(ckey); + mowgli_free(ckey); return NULL; } @@ -675,6 +700,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch soft_assert(dict->count == 0); place1 = &dict->root; *place1 = mowgli_heap_alloc(leaf_heap); + return_val_if_fail(*place1 != NULL, NULL); (*place1)->nibnum = -1; (*place1)->leaf.data = data; (*place1)->leaf.key = ckey; @@ -697,6 +723,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch { /* Insert new node below prev */ newnode = mowgli_heap_alloc(node_heap); + return_val_if_fail(newnode != NULL, NULL); newnode->nibnum = i; newnode->node.parent = prev; newnode->node.parent_val = val; @@ -744,6 +771,7 @@ struct patricia_leaf *mowgli_patricia_elem_add(mowgli_patricia_t *dict, const ch place1 = &newnode->node.down[val]; soft_assert(*place1 == NULL); *place1 = mowgli_heap_alloc(leaf_heap); + return_val_if_fail(*place1 != NULL, NULL); (*place1)->nibnum = -1; (*place1)->leaf.data = data; (*place1)->leaf.key = ckey; @@ -796,6 +824,9 @@ void mowgli_patricia_elem_delete(mowgli_patricia_t *dict, struct patricia_leaf * union patricia_elem *delem, *prev, *next; int val, i, used; + return_if_fail(dict != NULL); + return_if_fail(leaf != NULL); + delem = (union patricia_elem *)leaf; val = delem->leaf.parent_val; @@ -878,16 +909,22 @@ void *mowgli_patricia_retrieve(mowgli_patricia_t *dtree, const char *key) const char *mowgli_patricia_elem_get_key(struct patricia_leaf *leaf) { + return_val_if_fail(leaf != NULL, NULL); + return leaf->key; } void mowgli_patricia_elem_set_data(struct patricia_leaf *leaf, void *data) { + return_if_fail(leaf != NULL); + leaf->data = data; } void *mowgli_patricia_elem_get_data(struct patricia_leaf *leaf) { + return_val_if_fail(leaf != NULL, NULL); + return leaf->data; } diff --git a/src/libmowgli/mowgli_patricia.h b/src/libmowgli/container/patricia.h index 6c2c669..417ba62 100644 --- a/src/libmowgli/mowgli_patricia.h +++ b/src/libmowgli/container/patricia.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_patricia.h: Dictionary-based storage. + * patricia.h: Dictionary-based storage. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * Copyright (c) 2007-2008 Jilles Tjoelker <jilles -at- stack.nl> @@ -69,6 +69,13 @@ typedef struct mowgli_patricia_iteration_state_ mowgli_patricia_iteration_state_ extern mowgli_patricia_t *mowgli_patricia_create(void (*canonize_cb)(char *key)); /* + * mowgli_patricia_shutdown() deallocates all heaps used in patricia trees. This is + * useful on embedded devices with little memory, and/or when you know you won't need + * any more patricia trees. + */ +extern void mowgli_patricia_shutdown(void); + +/* * mowgli_patricia_destroy() destroys all entries in a dtree, and also optionally calls * a defined callback function to destroy any data attached to it. */ diff --git a/src/libmowgli/mowgli_queue.c b/src/libmowgli/container/queue.c index f27ff50..39150d3 100644 --- a/src/libmowgli/mowgli_queue.c +++ b/src/libmowgli/container/queue.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_queue.c: Double-ended queues, also known as deque. + * queue.c: Double-ended queues, also known as deque. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -26,7 +26,7 @@ static mowgli_heap_t *mowgli_queue_heap = NULL; void -mowgli_queue_init(void) +mowgli_queue_bootstrap(void) { mowgli_queue_heap = mowgli_heap_create(sizeof(mowgli_queue_t), 256, BH_NOW); @@ -39,6 +39,8 @@ mowgli_queue_shift(mowgli_queue_t *head, void *data) { mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); + return_val_if_fail(head != NULL, NULL); + out->next = head; out->data = data; @@ -60,6 +62,8 @@ mowgli_queue_push(mowgli_queue_t *head, void *data) { mowgli_queue_t *out = mowgli_heap_alloc(mowgli_queue_heap); + return_val_if_fail(head != NULL, NULL); + out->prev = head; out->data = data; @@ -74,6 +78,8 @@ mowgli_queue_remove(mowgli_queue_t *head) { mowgli_queue_t *out; + return_val_if_fail(head != NULL, NULL); + if (head->prev != NULL) head->prev->next = head->next; @@ -92,6 +98,8 @@ mowgli_queue_find(mowgli_queue_t *head, void *data) { mowgli_queue_t *n; + return_val_if_fail(head != NULL, NULL); + for (n = head; n != NULL; n = n->next) if (n->data == data) return n; @@ -104,6 +112,8 @@ mowgli_queue_remove_data(mowgli_queue_t *head, void *data) { mowgli_queue_t *n = mowgli_queue_find(head, data); + return_val_if_fail(head != NULL, NULL); + if (n != NULL) return mowgli_queue_remove(n); @@ -115,6 +125,8 @@ mowgli_queue_destroy(mowgli_queue_t *head) { mowgli_queue_t *n, *n2; + return_if_fail(head != NULL); + for (n = head, n2 = n ? n->next : NULL; n != NULL; n = n2, n2 = n ? n->next : NULL) mowgli_queue_remove(n); } @@ -125,6 +137,8 @@ mowgli_queue_skip(mowgli_queue_t *head, int nodes) mowgli_queue_t *n; int iter; + return_val_if_fail(head != NULL, NULL); + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->next, iter++); return n; @@ -136,6 +150,8 @@ mowgli_queue_rewind(mowgli_queue_t *head, int nodes) mowgli_queue_t *n; int iter; + return_val_if_fail(head != NULL, NULL); + for (iter = 0, n = head; n != NULL && iter < nodes; n = n->prev, iter++); return n; @@ -146,6 +162,8 @@ mowgli_queue_head(mowgli_queue_t *n) { mowgli_queue_t *tn; + return_val_if_fail(n != NULL, NULL); + for (tn = n; tn != NULL && tn->prev != NULL; tn = tn->prev); return tn; @@ -156,6 +174,8 @@ mowgli_queue_tail(mowgli_queue_t *n) { mowgli_queue_t *tn; + return_val_if_fail(n != NULL, NULL); + for (tn = n; tn != NULL && tn->next != NULL; tn = tn->next); return tn; @@ -203,6 +223,8 @@ mowgli_queue_length(mowgli_queue_t *head) int iter; mowgli_queue_t *n; + return_val_if_fail(head != NULL, -1); + for (n = head, iter = 0; n != NULL; n = n->next, iter++); return iter; diff --git a/src/libmowgli/mowgli_queue.h b/src/libmowgli/container/queue.h index 2d3b16b..7f8d995 100644 --- a/src/libmowgli/mowgli_queue.h +++ b/src/libmowgli/container/queue.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_queue.h: Double-ended queues, also known as deque. + * queue.h: Double-ended queues, also known as deque. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -26,7 +26,7 @@ typedef mowgli_iterator_t mowgli_queue_t; -extern void mowgli_queue_init(void); +extern void mowgli_queue_bootstrap(void); extern mowgli_queue_t *mowgli_queue_push(mowgli_queue_t *head, void *data); extern mowgli_queue_t *mowgli_queue_shift(mowgli_queue_t *head, void *data); extern mowgli_queue_t *mowgli_queue_remove(mowgli_queue_t *head); diff --git a/src/libmowgli/dns/Makefile b/src/libmowgli/dns/Makefile new file mode 100644 index 0000000..06fb36c --- /dev/null +++ b/src/libmowgli/dns/Makefile @@ -0,0 +1,20 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_DNS} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_DNS} + +SRCS = dns.c \ + dns_evloop_res.c \ + dns_evloop_reslib.c \ + dns_evloop_reslist_win32.c + +INCLUDES = dns.h \ + dns_evloop_res.h \ + dns_evloop_reslib.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/dns + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/dns/dns.c b/src/libmowgli/dns/dns.c new file mode 100644 index 0000000..eff5080 --- /dev/null +++ b/src/libmowgli/dns/dns.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dns.h" + +mowgli_dns_t * mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation) +{ + mowgli_dns_t *dns = mowgli_alloc(sizeof(mowgli_dns_t)); + const mowgli_dns_ops_t *ops; + + switch (implementation) + { + case MOWGLI_DNS_TYPE_CUSTOM: + return dns; + case MOWGLI_DNS_TYPE_ASYNC: + default: + ops = &mowgli_dns_evloop_resolver; + break; + } + + if (mowgli_dns_init(dns, eventloop, ops) != 0) + { + mowgli_free(dns); + return NULL; + } + + return dns; +} + +int mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowgli_dns_ops_t *ops) +{ + return_val_if_fail(dns != NULL, -1); + + dns->dns_ops = ops; + + return dns->dns_ops->mowgli_dns_init_func_t(dns, eventloop); +} + +void mowgli_dns_destroy(mowgli_dns_t *dns) +{ + dns->dns_ops->mowgli_dns_fini_func_t(dns); + + mowgli_free(dns); +} + +int mowgli_dns_restart(mowgli_dns_t *dns) +{ + return dns->dns_ops->mowgli_dns_restart_func_t(dns); +} + +void mowgli_dns_delete_query(mowgli_dns_t *dns, const mowgli_dns_query_t *query) +{ + dns->dns_ops->mowgli_dns_delete_query_func_t(dns, query); +} + +void mowgli_dns_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t *query, int type) +{ + dns->dns_ops->mowgli_dns_gethost_byname_func_t(dns, name, query, type); +} + +void mowgli_dns_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query) +{ + dns->dns_ops->mowgli_dns_gethost_byaddr_func_t(dns, addr, query); +} + diff --git a/src/libmowgli/dns/dns.h b/src/libmowgli/dns/dns.h new file mode 100644 index 0000000..9cbb6ee --- /dev/null +++ b/src/libmowgli/dns/dns.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_DNS_DNS_H__ +#define __MOWGLI_DNS_DNS_H__ + +#include "mowgli.h" + +/* Longest hostname we're willing to work with */ +#define MOWGLI_DNS_RES_HOSTLEN 512 + +/* Resolver types */ +#define MOWGLI_DNS_TYPE_CUSTOM 0 +#define MOWGLI_DNS_TYPE_ASYNC 1 +#define MOWGLI_DNS_TYPE_HELPER 2 + +/* Lookup types */ +#define MOWGLI_DNS_T_A 1 +#define MOWGLI_DNS_T_AAAA 28 +#define MOWGLI_DNS_T_PTR 12 +#define MOWGLI_DNS_T_CNAME 5 +#define MOWGLI_DNS_T_MX 15 +#define MOWGLI_DNS_T_TXT 16 +#define MOWGLI_DNS_T_SSHFP 44 +#define MOWGLI_DNS_T_NULL 10 + +/* Return codes */ +#define MOWGLI_DNS_RES_SUCCESS 0 +#define MOWGLI_DNS_RES_NXDOMAIN 1 +#define MOWGLI_DNS_RES_INVALID 2 +#define MOWGLI_DNS_RES_TIMEOUT 3 + +typedef struct _mowgli_dns_t mowgli_dns_t; +typedef struct _mowgli_dns_query_t mowgli_dns_query_t; +typedef struct _mowgli_dns_reply_t mowgli_dns_reply_t; + +typedef struct +{ + int (*mowgli_dns_init_func_t)(mowgli_dns_t *, mowgli_eventloop_t *); + void (*mowgli_dns_fini_func_t)(mowgli_dns_t *); + int (*mowgli_dns_restart_func_t)(mowgli_dns_t *); + void (*mowgli_dns_delete_query_func_t)(mowgli_dns_t *, const mowgli_dns_query_t *); + void (*mowgli_dns_gethost_byname_func_t)(mowgli_dns_t *, const char *, mowgli_dns_query_t *, int); + void (*mowgli_dns_gethost_byaddr_func_t)(mowgli_dns_t *, const struct sockaddr_storage *, mowgli_dns_query_t *); +} mowgli_dns_ops_t; + +struct _mowgli_dns_reply_t +{ + char *h_name; + mowgli_vio_sockaddr_t addr; +}; + +struct _mowgli_dns_t +{ + int dns_type; + const mowgli_dns_ops_t *dns_ops; + void *dns_state; +}; + +struct _mowgli_dns_query_t +{ + void *ptr; /* pointer used by callback to identify request */ + void (*callback) (mowgli_dns_reply_t * reply, int result, void *vptr); /* callback to call */ +}; + +extern mowgli_dns_t * mowgli_dns_create(mowgli_eventloop_t *eventloop, int implementation); +extern int mowgli_dns_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop, const mowgli_dns_ops_t *ops); +extern void mowgli_dns_destroy(mowgli_dns_t *dns); +extern int mowgli_dns_restart(mowgli_dns_t *dns); +extern void mowgli_dns_delete_query(mowgli_dns_t *dns, const mowgli_dns_query_t *query); +extern void mowgli_dns_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t *query, int type); +extern void mowgli_dns_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *addr, mowgli_dns_query_t *query); + +/* Pull in headers that depend on these types */ +#include "dns_evloop_res.h" +#include "dns_evloop_reslib.h" + +#endif + diff --git a/src/libmowgli/dns/dns_evloop_res.c b/src/libmowgli/dns/dns_evloop_res.c new file mode 100644 index 0000000..a97daf5 --- /dev/null +++ b/src/libmowgli/dns/dns_evloop_res.c @@ -0,0 +1,1017 @@ +/* + * A rewrite of Darren Reeds original res.c As there is nothing + * left of Darrens original code, this is now licensed by the hybrid group. + * (Well, some of the function names are the same, and bits of the structs..) + * You can use it where it is useful, free even. Buy us a beer and stuff. + * + * The authors takes no responsibility for any damage or loss + * of property which results from the use of this software. + * + * $Id: res.c 3301 2007-03-28 15:04:06Z jilles $ + * from Hybrid Id: res.c 459 2006-02-12 22:21:37Z db $ + * + * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code, + * added callbacks and reference counting of returned hostents. + * --Bleep (Thomas Helvey <tomh@inxpress.net>) + * + * This was all needlessly complicated for irc. Simplified. No more hostent + * All we really care about is the IP -> hostname mappings. Thats all. + * + * Apr 28, 2003 --cryogen and Dianora + * + * DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support + * removed, various robustness fixes + * + * 2006 --jilles and nenolod + * + * Clean up various crap, remove global state. Reindent because two space indent + * is hideous. Also remove ancient assumptions that don't make sense anymore (e.g., + * libmowgli targets C99, which specifies an 8-bit char). Pack all this stuff into + * its own namespace. Also gutted a lot of needless/one-use/few-line functions. + * Jesus, what were they thinking... + * + * 2012 --Elizacat + */ + +#include "mowgli.h" +#include "dns.h" + +#define MOWGLI_DNS_MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */ +#define MOWGLI_DNS_RES_MAXALIASES 35 /* maximum aliases allowed */ +#define MOWGLI_DNS_RES_MAXADDRS 35 /* maximum addresses allowed */ +#define MOWGLI_DNS_AR_TTL 600 /* TTL in seconds for dns cache entries */ + +/* RFC 1104/1105 wasn't very helpful about what these fields should be named, so for now, we'll + just name them this way. we probably should look at what named calls them or something. */ +#define MOWGLI_DNS_TYPE_SIZE (size_t)2 +#define MOWGLI_DNS_CLASS_SIZE (size_t)2 +#define MOWGLI_DNS_TTL_SIZE (size_t)4 +#define MOWGLI_DNS_RDLENGTH_SIZE (size_t)2 +#define MOWGLI_DNS_ANSWER_FIXED_SIZE (MOWGLI_DNS_TYPE_SIZE + MOWGLI_DNS_CLASS_SIZE + MOWGLI_DNS_TTL_SIZE + MOWGLI_DNS_RDLENGTH_SIZE) + +#define MOWGLI_DNS_MAXLINE 128 + +typedef struct +{ + mowgli_node_t node; + int id; + time_t ttl; + char type; + char queryname[MOWGLI_DNS_RES_HOSTLEN + 1]; /* name currently being queried */ + char retries; /* retry counter */ + char sends; /* number of sends (>1 means resent) */ + time_t sentat; + time_t timeout; + unsigned int lastns; /* index of last server sent to */ + struct sockaddr_storage addr; + char *name; + mowgli_dns_query_t *query; /* query callback for this request */ +} mowgli_dns_reslist_t; + +static mowgli_heap_t *reslist_heap = NULL; + +#ifndef _WIN32 +static int parse_resvconf(mowgli_dns_t *dns); +#else +static void parse_windows_resolvers(mowgli_dns_t *dns); +#endif + +static void timeout_resolver(void *arg); +static void add_nameserver(mowgli_dns_t *dns, const char *arg); +static int res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage *inp); +static void rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static mowgli_dns_reslist_t *make_request(mowgli_dns_t *dns, mowgli_dns_query_t * query); +static void do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t * query, const char *name, mowgli_dns_reslist_t *request, int); +static void do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t * query, const struct sockaddr_storage *, mowgli_dns_reslist_t *request); +static void query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static int send_res_msg(mowgli_dns_t *dns, const char *buf, int len, int count); +static void resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request); +static int check_question(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob); +static int proc_answer(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *, char *); +static mowgli_dns_reslist_t *find_id(mowgli_dns_t *dns, int id); +static mowgli_dns_reply_t *make_dnsreply(mowgli_dns_reslist_t *request); +static void res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); + +/* + * mowgli_dns_evloop_init - do everything we need to read the resolv.conf file + * and initialize the resolver file descriptor if needed + */ +int mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop) +{ + int i; + mowgli_dns_evloop_t *state; + + if (dns->dns_state == NULL) + dns->dns_state = mowgli_alloc(sizeof(mowgli_dns_evloop_t)); + + dns->dns_type = MOWGLI_DNS_TYPE_ASYNC; + + if (!reslist_heap) + reslist_heap = mowgli_heap_create(sizeof(mowgli_dns_reslist_t), 512, BH_LAZY); + + state = dns->dns_state; + + state->rand = mowgli_random_create(); + + state->nscount = 0; + +#ifndef _WIN32 + parse_resvconf(dns); +#else + parse_windows_resolvers(dns); +#endif + + if (state->nscount == 0) + { + mowgli_log("couldn't get resolv.conf entries, falling back to localhost resolver"); + add_nameserver(dns, "127.0.0.1"); + } + + for (i = 0; i < state->nscount; i++) + state->timeout_count[i] = 0; + + if (state->vio == NULL) + { + state->vio = mowgli_vio_create(dns); + if (mowgli_vio_socket(state->vio, state->nsaddr_list[0].addr.ss_family, SOCK_DGRAM, 0) != 0) + { + mowgli_log("start_resolver(): unable to open UDP resolver socket: %s", + state->vio->error.string); + return -1; + } + + state->eventloop = eventloop; + mowgli_vio_eventloop_attach(state->vio, state->eventloop); + mowgli_pollable_setselect(state->eventloop, state->vio->io, MOWGLI_EVENTLOOP_IO_READ, res_readreply); + state->timeout_resolver_timer = mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, 1); + } + + return 0; +} + +/* + * mowgli_dns_evloop_restart - reread resolv.conf, reopen socket + */ +int mowgli_dns_evloop_restart(mowgli_dns_t *dns) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + mowgli_dns_evloop_destroy(dns); + return mowgli_dns_evloop_init(dns, state->eventloop); +} + +/* mowgli_dns_evloop_destroy - finish us off */ +void mowgli_dns_evloop_destroy(mowgli_dns_t *dns) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + mowgli_vio_close(state->vio); + mowgli_vio_destroy(state->vio); + + mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); + + mowgli_free(state); + dns->dns_state = NULL; +} + +#ifndef _WIN32 + +/* parse_resvconf() inputs - NONE output - -1 if failure 0 if success side effects - fills in + * state->nsaddr_list */ +static int parse_resvconf(mowgli_dns_t *dns) +{ + char *p; + char *opt; + char *arg; + char input[MOWGLI_DNS_MAXLINE]; + FILE *file; + mowgli_dns_evloop_t *state = dns->dns_state; + + /* XXX "/etc/resolv.conf" should be from a define in setup.h perhaps for cygwin support etc. + * this hardcodes it to unix for now -db */ + if ((file = fopen("/etc/resolv.conf", "r")) == NULL) + return -1; + + while (fgets(input, sizeof(input), file) != NULL) + { + /* blow away any newline */ + if ((p = strpbrk(input, "\r\n")) != NULL) + *p = '\0'; + + p = input; + /* skip until something thats not a space is seen */ + while (isspace(*p)) + p++; + /* if at this point, have a '\0' then continue */ + if (*p == '\0') + continue; + + /* Ignore comment lines immediately */ + if (*p == '#' || *p == ';') + continue; + + /* skip until a space is found */ + opt = p; + while (!isspace(*p) && *p != '\0') + p++; + if (*p == '\0') + continue; /* no arguments?.. ignore this line */ + /* blow away the space character */ + *p++ = '\0'; + + /* skip these spaces that are before the argument */ + while (isspace(*p)) + p++; + /* Now arg should be right where p is pointing */ + arg = p; + if ((p = strpbrk(arg, " \t")) != NULL) + *p = '\0'; /* take the first word */ + + if (strcmp(opt, "domain") == 0) + mowgli_strlcpy(state->domain, arg, sizeof(state->domain)); + else if (strcmp(opt, "nameserver") == 0) + add_nameserver(dns, arg); + } + + fclose(file); + return 0; +} + +#else + +extern int mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size); + +static void +parse_windows_resolvers(mowgli_dns_t *dns) +{ + char ns_buf[4096]; + char *server; + + mowgli_dns_get_windows_nameservers(ns_buf, sizeof ns_buf); + + for(server = strtok(ns_buf, ","); server != NULL; server = strtok(NULL, ",")) + add_nameserver(dns, server); +} + +#endif + + +/* add_nameserver() input - either an IPV4 address in dotted quad or an IPV6 address in : format + * output - NONE side effects - entry in state->nsaddr_list is filled in as needed */ +static void add_nameserver(mowgli_dns_t *dns, const char *arg) +{ + struct addrinfo hints, *res; + mowgli_dns_evloop_t *state = dns->dns_state; + +#ifdef DEBUG + mowgli_log("add_nameserver(): %s", arg); +#endif + + /* Done max number of nameservers? */ + if (state->nscount >= MOWGLI_DNS_MAXNS) + { + mowgli_log("Too many nameservers, ignoring %s", arg); + return; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + if (getaddrinfo(arg, "domain", &hints, &res)) + return; + + if (res == NULL) + return; + + memcpy(&state->nsaddr_list[state->nscount].addr, res->ai_addr, res->ai_addrlen); + state->nsaddr_list[state->nscount].addrlen = res->ai_addrlen; + state->nscount++; + freeaddrinfo(res); +} + +/* + * int + * res_ourserver(dns, inp) + * looks up "inp" in state->nsaddr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + * revised for ircd, cryogen(stu) may03 + * rewritten by Elizacat 25mar12 + */ +static int res_ourserver(mowgli_dns_t *dns, const struct sockaddr_storage * inp) +{ + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + for (ns = 0; ns < state->nscount; ns++) + { + const struct sockaddr_storage *srv = &state->nsaddr_list[ns].addr; + + /* could probably just memcmp(srv, inp, srv.ss_len) here but we'll air on the side of + caution - stu */ + switch (srv->ss_family) + { + case AF_INET6: + { + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)srv; + const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp; + + if (srv->ss_family == inp->ss_family && v6->sin6_port == v6in->sin6_port) + { + if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr, + sizeof(struct in6_addr)) == 0) || + (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any, + sizeof(struct in6_addr)) == 0)) + { + state->timeout_count[ns] = 0; + return 1; + } + } + break; + } + case AF_INET: + { + const struct sockaddr_in *v4 = (const struct sockaddr_in *)srv; + const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp; + + if (srv->ss_family == inp->ss_family && v4->sin_port == v4in->sin_port) + { + if ((v4->sin_addr.s_addr == INADDR_ANY) + || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr)) + { + state->timeout_count[ns] = 0; + return 1; + } + } + break; + } + default: + break; + } + } + + return 0; +} + +/* + * timeout_query_list - Remove queries from the list which have been + * there too long without being resolved. + */ +static time_t timeout_query_list(mowgli_dns_t *dns, time_t now) +{ + mowgli_node_t *ptr; + mowgli_node_t *next_ptr; + mowgli_dns_reslist_t *request; + time_t next_time = 0; + time_t timeout = 0; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) + { + request = ptr->data; + timeout = request->sentat + request->timeout; + + if (now >= timeout) + { + if (--request->retries <= 0) + { + (*request->query->callback) (NULL, MOWGLI_DNS_RES_TIMEOUT, request->query->ptr); + rem_request(dns, request); + continue; + } + else + { + state->timeout_count[request->lastns]++; + request->sentat = now; + request->timeout += request->timeout; + resend_query(dns, request); + } + } + + if ((next_time == 0) || timeout < next_time) + next_time = timeout; + } + + return (next_time > now) ? next_time : (now + MOWGLI_DNS_AR_TTL); +} + +/* + * timeout_resolver - check request list + */ +static void timeout_resolver(void *arg) +{ + mowgli_dns_t *dns = arg; + mowgli_dns_evloop_t *state = dns->dns_state; + time_t next; + + next = timeout_query_list(dns, mowgli_eventloop_get_time(state->eventloop)); + + /* Reschedule */ + mowgli_timer_destroy(state->eventloop, state->timeout_resolver_timer); + mowgli_timer_add(state->eventloop, "timeout_resolver", timeout_resolver, dns, next); +} + + +/* + * mowgli_dns_evloop_add_local_domain - Add the domain to hostname, if it is missing + * (as suggested by eps@TOASTER.SFSU.EDU) + */ +void mowgli_dns_evloop_add_local_domain(mowgli_dns_t *dns, char *hname, size_t size) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + /* try to fix up unqualified names */ + if (strchr(hname, '.') == NULL) + { + if (state->domain[0]) + { + size_t len = strlen(hname); + + if ((strlen(state->domain) + len + 2) < size) + { + hname[len++] = '.'; + strcpy(hname + len, state->domain); + } + } + } +} + +/* + * rem_request - remove a request from the list. + * This must also free any memory that has been allocated for + * temporary storage of DNS results. + */ +static void rem_request(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + mowgli_dns_evloop_t *state = dns->dns_state; + + return_if_fail(request != NULL); + + mowgli_node_delete(&request->node, &state->request_list); + mowgli_free(request->name); + mowgli_heap_free(reslist_heap, request); +} + +/* + * make_request - Create a DNS request record for the server. + */ +static mowgli_dns_reslist_t *make_request(mowgli_dns_t *dns, mowgli_dns_query_t * query) +{ + mowgli_dns_reslist_t *request = mowgli_heap_alloc(reslist_heap); + mowgli_dns_evloop_t *state = dns->dns_state; + + request->sentat = mowgli_eventloop_get_time(state->eventloop); + request->retries = 3; + request->timeout = 4; /* start at 4 and exponential inc. */ + request->query = query; + + mowgli_node_add(request, &request->node, &state->request_list); + + return request; +} + +/* + * mowgli_dns_evloop_delete_queries - cleanup outstanding queries + * for which there no longer exist clients or conf lines. + */ +void mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t * query) +{ + mowgli_node_t *ptr; + mowgli_node_t *next_ptr; + mowgli_dns_reslist_t *request; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH_SAFE(ptr, next_ptr, state->request_list.head) + { + if ((request = ptr->data) != NULL) + { + if (query == request->query) + rem_request(dns, request); + } + } +} + +/* + * retryfreq - determine how many queries to wait before resending + * if there have been that many consecutive timeouts + */ +static inline int retryfreq(int timeouts) +{ + int i; + int counter = 1; + const int max_retries = 5; + + for (i = 0; i < (timeouts < max_retries ? timeouts : max_retries); i++) + counter *= 3; + + return counter; +} + +/* + * send_res_msg - sends msg to a nameserver. + * This should reflect /etc/resolv.conf. + * Returns number of nameserver successfully sent to + * or -1 if no successful sends. + */ +static int send_res_msg(mowgli_dns_t *dns, const char *rmsg, int len, int rcount) +{ + int i; + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + state->retrycnt++; + /* First try a nameserver that seems to work. Every once in a while, try a possibly broken one + * to check if it is working again. */ + for (i = 0; i < state->nscount; i++) + { + ns = (i + rcount - 1) % state->nscount; + + if (state->timeout_count[ns] && state->retrycnt % retryfreq(state->timeout_count[ns])) + continue; + + if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) + return ns; + } + + /* No known working nameservers, try some broken one. */ + for (i = 0; i < state->nscount; i++) + { + ns = (i + rcount - 1) % state->nscount; + if (!state->timeout_count[ns]) + continue; + + if (mowgli_vio_sendto(state->vio, rmsg, len, &state->nsaddr_list[ns]) == len) + return ns; + } + + return -1; +} + +/* + * find_id - find a dns request id (id is determined by dn_mkquery) + */ +static mowgli_dns_reslist_t *find_id(mowgli_dns_t *dns, int id) +{ + mowgli_node_t *ptr; + mowgli_dns_reslist_t *request; + mowgli_dns_evloop_t *state = dns->dns_state; + + MOWGLI_ITER_FOREACH(ptr, state->request_list.head) + { + request = ptr->data; + + if (request->id == id) + return request; + } + + return NULL; +} + +/* + * mowgli_dns_evloop_gethost_byname - get host address from name + * + */ +void mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *name, mowgli_dns_query_t * query, int type) +{ + return_if_fail(name != NULL); + + do_query_name(dns, query, name, NULL, type); +} + +/* + * mowgli_dns_evloop_gethost_byaddr - get host name from address + */ +void mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage * addr, mowgli_dns_query_t * query) +{ + return_if_fail(addr != NULL); + + do_query_number(dns, query, addr, NULL); +} + +/* + * do_query_name - nameserver lookup name + */ +static void do_query_name(mowgli_dns_t *dns, mowgli_dns_query_t * query, const char *name, mowgli_dns_reslist_t *request, int type) +{ + char host_name[MOWGLI_DNS_RES_HOSTLEN + 1]; + + mowgli_strlcpy(host_name, name, MOWGLI_DNS_RES_HOSTLEN + 1); + mowgli_dns_evloop_add_local_domain(dns, host_name, MOWGLI_DNS_RES_HOSTLEN); + + if (request == NULL) + { + request = make_request(dns, query); + request->name = mowgli_strdup(host_name); + } + + mowgli_strlcpy(request->queryname, host_name, sizeof(request->queryname)); + request->type = type; + query_name(dns, request); +} + +/* + * do_query_number - Use this to do reverse IP# lookups. + */ +static void do_query_number(mowgli_dns_t *dns, mowgli_dns_query_t * query, const struct sockaddr_storage * addr, + mowgli_dns_reslist_t *request) +{ + const unsigned char *cp; + const size_t size = addr->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); + + if (request == NULL) + { + request = make_request(dns, query); + memcpy(&request->addr, addr, size); + request->name = (char *)mowgli_alloc(MOWGLI_DNS_RES_HOSTLEN + 1); + } + + if (addr->ss_family == AF_INET) + { + const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr; + cp = (const unsigned char *)&v4->sin_addr.s_addr; + + sprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp[3]), + (unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0])); + } + else if (addr->ss_family == AF_INET6) + { + int i; + char *rqptr = request->queryname; + const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr; + cp = (const unsigned char *)&v6->sin6_addr.s6_addr; + + for(i = 15; i >= 0; i--, rqptr += 4) + { + sprintf(rqptr, "%1x.%1x.", + (unsigned int)(cp[i] & 0xf), + (unsigned int)(cp[i] >> 4)); + } + + strcpy(rqptr, ".ip6.arpa"); + } + else + { + mowgli_log("do_query_number() called with invalid sockaddr_storage %d", addr->ss_family); + return; + } + + + request->type = MOWGLI_DNS_T_PTR; + query_name(dns, request); +} + +/* + * query_name - generate a query based on class, type and name. + */ +static void query_name(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + char buf[MOWGLI_DNS_MAXPACKET]; + int request_len = 0; + int ns; + mowgli_dns_evloop_t *state = dns->dns_state; + + memset(buf, 0, sizeof(buf)); + + if ((request_len = + mowgli_dns_res_mkquery(request->queryname, MOWGLI_DNS_C_IN, request->type, (unsigned char *)buf, + sizeof(buf))) > 0) + { + mowgli_dns_resheader_t *header = (mowgli_dns_resheader_t *) buf; + /* + * generate an unique id + * NOTE: we don't have to worry about converting this to and from + * network byte order, the nameserver does not interpret this value + * and returns it unchanged + */ + do + { + header->id = (header->id + mowgli_random_int(state->rand)) & 0xffff; + } + while (find_id(dns, header->id)); + + request->id = header->id; + ++request->sends; + + ns = send_res_msg(dns, buf, request_len, request->sends); + if (ns != -1) + request->lastns = ns; + } +} + +static void resend_query(mowgli_dns_t *dns, mowgli_dns_reslist_t *request) +{ + switch (request->type) + { + case MOWGLI_DNS_T_PTR: + do_query_number(dns, NULL, &request->addr, request); + break; + case MOWGLI_DNS_T_A: + case MOWGLI_DNS_T_AAAA: + do_query_name(dns, NULL, request->name, request, request->type); + break; + default: + break; + } +} + +/* + * check_question - check if the reply really belongs to the + * name we queried (to guard against late replies from previous + * queries with the same id). + */ +static int check_question(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob) +{ + char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 1]; /* working buffer */ + unsigned char *current; /* current position in buf */ + int n; /* temp count */ + + current = (unsigned char *)buf + sizeof(mowgli_dns_resheader_t); + + if (header->qdcount != 1) + return 0; + + n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf, sizeof(hostbuf)); + + if (n <= 0) + return 0; + + if (strcasecmp(hostbuf, request->queryname)) + return 0; + + return 1; +} + +/* + * proc_answer - process name server reply + */ +static int proc_answer(mowgli_dns_t *dns, mowgli_dns_reslist_t *request, mowgli_dns_resheader_t * header, char *buf, char *eob) +{ + char hostbuf[MOWGLI_DNS_RES_HOSTLEN + 100]; /* working buffer */ + unsigned char *current; /* current position in buf */ + int query_class; /* answer class */ + int type; /* answer type */ + int n; /* temp count */ + int rd_length; + + current = (unsigned char *)buf + sizeof(mowgli_dns_resheader_t); + + for (; header->qdcount > 0; --header->qdcount) + { + if ((n = mowgli_dns_dn_skipname(current, (unsigned char *)eob)) < 0) + return 0; + + current += (size_t) n + MOWGLI_DNS_QFIXEDSIZE; + } + + /* process each answer sent to us. */ + while (header->ancount > 0 && (char *)current < eob) + { + header->ancount--; + + n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf, + sizeof(hostbuf)); + + /* Broken message (< 0) or no more answers left (== 0) */ + if (n <= 0) + return 0; + + hostbuf[MOWGLI_DNS_RES_HOSTLEN] = '\0'; + + /* With Address arithmetic you have to be very anal -- this code was not working on alpha due + * to that (spotted by rodder/jailbird/dianora) */ + current += (size_t) n; + + if (!(((char *)current + MOWGLI_DNS_ANSWER_FIXED_SIZE) < eob)) + break; + + type = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_TYPE_SIZE; + + query_class = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_CLASS_SIZE; + + /* We may use this later at some point so... eliminate bogus GCC warning */ + (void)query_class; + + request->ttl = mowgli_dns_ns_get32(current); + current += MOWGLI_DNS_TTL_SIZE; + + rd_length = mowgli_dns_ns_get16(current); + current += MOWGLI_DNS_RDLENGTH_SIZE; + + /* Wait to set request->type until we verify this structure */ + switch (type) + { + case MOWGLI_DNS_T_A: + { + struct sockaddr_in *v4; + + if (request->type != MOWGLI_DNS_T_A) + return 0; + + /* check for invalid rd_length or too many addresses */ + if (rd_length != sizeof(struct in_addr)) + return 0; + + v4 = (struct sockaddr_in *)&request->addr; + v4->sin_family = AF_INET; + memcpy(&v4->sin_addr, current, sizeof(struct in_addr)); + + return 1; + } + case MOWGLI_DNS_T_AAAA: + { + struct sockaddr_in6 *v6; + + if (request->type != MOWGLI_DNS_T_AAAA) + return 0; + + if (rd_length != sizeof(struct in6_addr)) + return 0; + + v6 = (struct sockaddr_in6 *)&request->addr; + v6->sin6_family = AF_INET6; + memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr)); + + return 1; + } + case MOWGLI_DNS_T_PTR: + if (request->type != MOWGLI_DNS_T_PTR) + return 0; + + n = mowgli_dns_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, + hostbuf, sizeof(hostbuf)); + + /* Broken message or no more answers left */ + if (n <= 0) + return 0; + + mowgli_strlcpy(request->name, hostbuf, MOWGLI_DNS_RES_HOSTLEN + 1); + + return 1; + case MOWGLI_DNS_T_CNAME: + /* real answer will follow */ + current += rd_length; + break; + default: + /* XXX I'd rather just throw away the entire bogus thing but its possible its just a + * broken nameserver with still valid answers. But lets do some rudimentary logging for + * now... */ + mowgli_log("proc_answer(): bogus type %d", type); + break; + } + } + + return 1; +} + +/* + * res_read_single_reply - read a dns reply from the nameserver and process it. + * Return value: 1 if a packet was read, 0 otherwise + */ +static int res_read_single_reply(mowgli_dns_t *dns) +{ + char buf[sizeof(mowgli_dns_resheader_t) + MOWGLI_DNS_MAXPACKET] + /* Sparc and alpha need 16bit-alignment for accessing header->id (which is uint16_t). + Because of the header = (mowgli_dns_resheader_t*) buf; later on, this is neeeded. --FaUl */ +#if defined(__sparc__) || defined(__alpha__) + __attribute__ ((aligned(16))) +#endif + ; + mowgli_dns_resheader_t *header; + mowgli_dns_reslist_t *request = NULL; + mowgli_dns_reply_t *reply = NULL; + int rc; + int answer_count; + mowgli_vio_sockaddr_t lsin; + mowgli_dns_evloop_t *state = dns->dns_state; + + rc = mowgli_vio_recvfrom(state->vio, buf, sizeof(buf), &lsin); + + /* No packet */ + if (rc == 0 || rc == -1) + return 0; + + /* Too small */ + if (rc <= (int)(sizeof(mowgli_dns_resheader_t))) + return 1; + + /* + * convert DNS reply reader from Network byte order to CPU byte order. + */ + header = (mowgli_dns_resheader_t *) buf; + header->ancount = ntohs(header->ancount); + header->qdcount = ntohs(header->qdcount); + header->nscount = ntohs(header->nscount); + header->arcount = ntohs(header->arcount); + + /* response for an id which we have already received an answer for + * just ignore this response. */ + if ((request = find_id(dns, header->id)) == 0) + return 1; + + /* check against possibly fake replies */ + if (!res_ourserver(dns, &lsin.addr)) + return 1; + + if (!check_question(dns, request, header, buf, buf + rc)) + return 1; + + if ((header->rcode != MOWGLI_DNS_NO_ERRORS) || (header->ancount == 0)) + { + if (header->rcode == MOWGLI_DNS_NXDOMAIN) + { + (*request->query->callback) (NULL, MOWGLI_DNS_RES_NXDOMAIN, request->query->ptr); + rem_request(dns, request); + } + else + { + /* + * If a bad error was returned, we stop here and dont send + * send any more (no retries granted). + */ + (*request->query->callback) (NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + } + return 1; + } + + /* If this fails there was an error decoding the received packet, + * give up. -- jilles + */ + answer_count = proc_answer(dns, request, header, buf, buf + rc); + + if (answer_count) + { + if (request->type == MOWGLI_DNS_T_PTR) + { + if (request->name == NULL) + { + /* got a PTR response with no name, something bogus is happening + * don't bother trying again, the client address doesn't resolve + */ + (*request->query->callback) (reply, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + return 1; + } + + /* Lookup the 'authoritative' name that we were given for the + * ip#. */ + if (request->addr.ss_family == AF_INET6) + mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_AAAA); + else + mowgli_dns_evloop_gethost_byname(dns, request->name, request->query, MOWGLI_DNS_T_A); + rem_request(dns, request); + } + else + { + /* got a name and address response, client resolved */ + reply = make_dnsreply(request); + (*request->query->callback) (reply, MOWGLI_DNS_RES_SUCCESS, request->query->ptr); + mowgli_free(reply); + rem_request(dns, request); + } + } + else + { + /* couldn't decode, give up -- jilles */ + (*request->query->callback) (NULL, MOWGLI_DNS_RES_INVALID, request->query->ptr); + rem_request(dns, request); + } + + return 1; +} + +static mowgli_dns_reply_t *make_dnsreply(mowgli_dns_reslist_t *request) +{ + mowgli_dns_reply_t *cp; + return_val_if_fail(request != 0, NULL); + + cp = (mowgli_dns_reply_t *) mowgli_alloc(sizeof(mowgli_dns_reply_t)); + + cp->h_name = request->name; + memcpy(&cp->addr, &request->addr, sizeof(cp->addr)); + return cp; +} + +static void res_readreply(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_dns_t *dns = userdata; + while (res_read_single_reply(dns)); +} + +/* DNS ops for this resolver */ +const mowgli_dns_ops_t mowgli_dns_evloop_resolver = { + .mowgli_dns_init_func_t = mowgli_dns_evloop_init, + .mowgli_dns_fini_func_t = mowgli_dns_evloop_destroy, + .mowgli_dns_restart_func_t = mowgli_dns_evloop_restart, + .mowgli_dns_delete_query_func_t = mowgli_dns_evloop_delete_queries, + .mowgli_dns_gethost_byname_func_t = mowgli_dns_evloop_gethost_byname, + .mowgli_dns_gethost_byaddr_func_t = mowgli_dns_evloop_gethost_byaddr, +}; + diff --git a/src/libmowgli/dns/dns_evloop_res.h b/src/libmowgli/dns/dns_evloop_res.h new file mode 100644 index 0000000..3973533 --- /dev/null +++ b/src/libmowgli/dns/dns_evloop_res.h @@ -0,0 +1,44 @@ +/* + * res.h for referencing functions in res.c, reslib.c + * + * Originally from Charybdis (before that, hybrid), but very little of the + * original remains, so... + */ + +#ifndef __MOWGLI_DNS_RES_H__ +#define __MOWGLI_DNS_RES_H__ + +/* Maximum number of nameservers we track */ +#define MOWGLI_DNS_MAXNS 10 + +typedef struct +{ + mowgli_vio_sockaddr_t nsaddr_list[MOWGLI_DNS_MAXNS]; + int nscount; + + int retrycnt; + + int timeout_count[MOWGLI_DNS_MAXNS]; + + mowgli_vio_t *vio; + mowgli_eventloop_t *eventloop; + mowgli_eventloop_timer_t *timeout_resolver_timer; + + mowgli_list_t request_list; + + mowgli_random_t *rand; + + char domain[MOWGLI_DNS_RES_HOSTLEN]; +} mowgli_dns_evloop_t; + +extern int mowgli_dns_evloop_init(mowgli_dns_t *dns, mowgli_eventloop_t *eventloop); +extern int mowgli_dns_evloop_restart(mowgli_dns_t *dns); +extern void mowgli_dns_evloop_destroy(mowgli_dns_t *dns); +extern void mowgli_dns_evloop_delete_queries(mowgli_dns_t *dns, const mowgli_dns_query_t *); +extern void mowgli_dns_evloop_gethost_byname(mowgli_dns_t *dns, const char *, mowgli_dns_query_t *, int); +extern void mowgli_dns_evloop_gethost_byaddr(mowgli_dns_t *dns, const struct sockaddr_storage *, mowgli_dns_query_t *); +extern void mowgli_dns_evloop_add_local_domain(mowgli_dns_t *dns, char *, size_t); + +extern const mowgli_dns_ops_t mowgli_dns_evloop_resolver; + +#endif diff --git a/src/libmowgli/dns/dns_evloop_reslib.c b/src/libmowgli/dns/dns_evloop_reslib.c new file mode 100644 index 0000000..edefbe7 --- /dev/null +++ b/src/libmowgli/dns/dns_evloop_reslib.c @@ -0,0 +1,1102 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* Original copyright ISC as above. Code modified specifically for ircd use from the following + * orginal files in bind ... res_comp.c ns_name.c ns_netint.c res_init.c - Dianora */ + +#include "dns.h" + +#ifdef _WIN32 +#define EMSGSIZE WSAEMSGSIZE +#endif + +#define MOWGLI_DNS_NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define MOWGLI_DNS_LABELTYPE_BITSTRING 0x41 + +/* from Hybrid Id: reslib.c 177 2005-10-22 09:05:05Z michael $ */ + +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 16 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 32 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 48 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 64 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 96 */ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 112 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 128 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 256 */ +}; + +static const char digits[] = "0123456789"; + +static int labellen(const unsigned char *lp); +static bool mowgli_dns_is_special(int ch); +static bool mowgli_dns_is_printable(int ch); +static int mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom); +static int mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr); +static int mowgli_dns_dn_find(const unsigned char *, const unsigned char *, const unsigned char *const *, const unsigned char *const *); +static int mowgli_dns_encode_bitsring(const char **, const char *, unsigned char **, unsigned char **, const char *); +static int mowgli_dns_ns_name_uncompress(const unsigned char *, const unsigned char *, const unsigned char *, char *, size_t); +static int mowgli_dns_ns_name_unpack(const unsigned char *, const unsigned char *, const unsigned char *, unsigned char *, size_t); +static int mowgli_dns_ns_name_ntop(const char *, char *, size_t); +static int mowgli_dns_ns_name_skip(const unsigned char **, const unsigned char *); +static int mowgli_dns_mklower(int ch); + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'rmsg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +mowgli_dns_dn_expand(const unsigned char *rmsg, const unsigned char *eom, + const unsigned char *src, char *dst, int dstsiz) +{ + int n = mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, (size_t) dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return n; +} + +/* + * mowgli_dns_ns_name_uncompress(rmsg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +static int +mowgli_dns_ns_name_uncompress(const unsigned char *rmsg, const unsigned char *eom, + const unsigned char *src, char *dst, size_t dstsiz) +{ + unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; + int n; + + if ((n = mowgli_dns_ns_name_unpack(rmsg, eom, src, tmp, sizeof tmp)) == -1) + return -1; + if (mowgli_dns_ns_name_ntop((char *)tmp, dst, dstsiz) == -1) + return -1; + return n; +} + +/* + * mowgli_dns_ns_name_unpack(rmsg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +static int +mowgli_dns_ns_name_unpack(const unsigned char *rmsg, const unsigned char *eom, const unsigned char *src, unsigned char *dst, size_t dstsiz) +{ + const unsigned char *srcp, *dstlim; + unsigned char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < rmsg || srcp >= eom) + { + errno = EMSGSIZE; + return -1; + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) + { + /* Check for indirection. */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: + case MOWGLI_DNS_NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) + { + errno = EMSGSIZE; + return -1; + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) + { + errno = EMSGSIZE; + return -1; + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, l); + dstp += l; + srcp += l; + break; + + case MOWGLI_DNS_NS_CMPRSFLAGS: + if (srcp >= eom) + { + errno = EMSGSIZE; + return -1; + } + if (len < 0) + len = srcp - src + 1; + srcp = rmsg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < rmsg || srcp >= eom) + { /* Out of range. */ + errno = EMSGSIZE; + return -1; + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - rmsg) + { + errno = EMSGSIZE; + return -1; + } + break; + + default: + errno = EMSGSIZE; + return -1; /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return len; +} + +/* + * mowgli_dns_ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to mowgli_dns_is_printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +static int mowgli_dns_ns_name_ntop(const char *src, char *dst, size_t dstsiz) +{ + const char *cp; + char *dn, *eom; + unsigned char c; + unsigned int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) + { + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return -1; + } + if (dn != dst) + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = '.'; + } + if ((l = labellen((const unsigned char *)(cp - 1))) < 0) + { + errno = EMSGSIZE; /* XXX */ + return -1; + } + if (dn + l >= eom) + { + errno = EMSGSIZE; + return -1; + } + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) + { + int m; + + if (n != MOWGLI_DNS_LABELTYPE_BITSTRING) + { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return -1; + } + if ((m = mowgli_dns_decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return -1; + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) + { + c = *cp++; + if (mowgli_dns_is_special(c)) + { + if (dn + 1 >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = '\\'; + *dn++ = (char)c; + } + else if (!mowgli_dns_is_printable(c)) + { + if (dn + 3 >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } + else + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = (char)c; + } + } + } + if (dn == dst) + { + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = '.'; + } + if (dn >= eom) + { + errno = EMSGSIZE; + return -1; + } + *dn++ = '\0'; + return dn - dst; +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +static int +mowgli_dns_dn_comp(const char *src, unsigned char *dst, int dstsiz, + unsigned char **dnptrs, unsigned char **lastdnptr) +{ + return mowgli_dns_ns_name_compress(src, dst, (size_t) dstsiz, dnptrs, lastdnptr); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom) +{ + const unsigned char *saveptr = ptr; + + if (mowgli_dns_ns_name_skip(&ptr, eom) == -1) + return -1; + return ptr - saveptr; +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +static int mowgli_dns_ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) +{ + const unsigned char *cp; + unsigned int n; + int l; + + cp = *ptrptr; + + while (cp < eom && (n = *cp++) != 0) + { + /* Check for indirection. */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: /* normal case, n == len */ + cp += n; + continue; + case MOWGLI_DNS_NS_TYPE_ELT: /* EDNS0 extended label */ + if ((l = labellen(cp - 1)) < 0) + { + errno = EMSGSIZE; /* XXX */ + return -1; + } + + cp += l; + continue; + case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return -1; + } + + break; + } + + if (cp > eom) + { + errno = EMSGSIZE; + return -1; + } + + *ptrptr = cp; + return 0; +} + +unsigned int mowgli_dns_ns_get16(const unsigned char *src) +{ + unsigned int dst; + + MOWGLI_DNS_NS_GET16(dst, src); + return dst; +} + +unsigned long mowgli_dns_ns_get32(const unsigned char *src) +{ + unsigned long dst; + + MOWGLI_DNS_NS_GET32(dst, src); + return dst; +} + +void mowgli_dns_ns_put16(unsigned int src, unsigned char *dst) +{ + MOWGLI_DNS_NS_PUT16(src, dst); +} + +void mowgli_dns_ns_put32(unsigned long src, unsigned char *dst) +{ + MOWGLI_DNS_NS_PUT32(src, dst); +} + +/* From ns_name.c */ + +/* + * mowgli_dns_is_special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted mowgli_dns_is_special ("in need of quoting") ? + * return: + * boolean. + */ +static bool mowgli_dns_is_special(int ch) +{ + switch (ch) + { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return true; + default: + return false; + } +} + +static int labellen(const unsigned char *lp) +{ + int bitlen; + unsigned char l = *lp; + + if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + /* should be avoided by the caller */ + return -1; + + if ((l & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_TYPE_ELT) + { + if (l == MOWGLI_DNS_LABELTYPE_BITSTRING) + { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + + return (bitlen + 7) / 8 + 1; + } + + return -1; /* unknwon ELT */ + } + + return l; +} + + +/* + * mowgli_dns_is_printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static bool mowgli_dns_is_printable(int ch) +{ + return (ch > 0x20 && ch < 0x7f) ? true : false; +} + +static int mowgli_dns_decode_bitstring(const char **cpp, char *dn, const char *eom) +{ + const char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return -1; + + cp++; + dn += sprintf(dn, "\\[x"); + for (b = blen; b > 7; b -= 8, cp++) + dn += sprintf(dn, "%02x", *cp & 0xff); + if (b > 4) + { + tc = *cp++; + dn += sprintf(dn, "%02x", tc & (0xff << (8 - b))); + } + else if (b > 0) + { + tc = *cp++; + dn += sprintf(dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); + } + dn += sprintf(dn, "/%d]", blen); + + *cpp = cp; + return (dn - beg); +} + +/* + * mowgli_dns_ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ +static int mowgli_dns_ns_name_pton(const char *src, unsigned char *dst, size_t dstsiz) +{ + unsigned char *label, *bp, *eom; + char *cp; + int c, n, escaped, e = 0; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + + while ((c = *src++) != 0) + { + if (escaped) + { + if (c == '[') + { /* start a bit string label */ + if ((cp = strchr(src, ']')) == NULL) + { + errno = EINVAL; /* ??? */ + return -1; + } + if ((e = mowgli_dns_encode_bitsring(&src, cp + 2, &label, &bp, (const char *)eom)) != 0) + { + errno = e; + return -1; + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') + { + errno = EINVAL; + return -1; + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) + { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) + { + errno = EMSGSIZE; + return -1; + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || (cp = strchr(digits, c)) == NULL) + { + errno = EMSGSIZE; + return -1; + } + n += (cp - digits); + if (n > 255) + { + errno = EMSGSIZE; + return -1; + } + c = n; + } + escaped = 0; + } + else if (c == '\\') + { + escaped = 1; + continue; + } + else if (c == '.') + { + c = (bp - label - 1); + if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0) + { /* Label too big. */ + errno = EMSGSIZE; + return -1; + } + if (label >= eom) + { + errno = EMSGSIZE; + return -1; + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') + { + if (c != 0) + { + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + *bp++ = '\0'; + } + if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) + { + errno = EMSGSIZE; + return -1; + } + return (1); + } + if (c == 0 || *src == '.') + { + errno = EMSGSIZE; + return -1; + } + label = bp++; + continue; + } + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + *bp++ = (unsigned char)c; + } + c = (bp - label - 1); + if ((c & MOWGLI_DNS_NS_CMPRSFLAGS) != 0) + { /* Label too big. */ + errno = EMSGSIZE; + return -1; + } + done: + if (label >= eom) + { + errno = EMSGSIZE; + return -1; + } + *label = c; + if (c != 0) + { + if (bp >= eom) + { + errno = EMSGSIZE; + return -1; + } + *bp++ = 0; + } + + if ((bp - dst) > MOWGLI_DNS_NS_MAXCDNAME) + { /* src too big */ + errno = EMSGSIZE; + return -1; + } + + return 0; +} + +/* + * mowgli_dns_ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +static int +mowgli_dns_ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, + unsigned char **dnptrs, unsigned char **lastdnptr) +{ + unsigned char *dstp; + unsigned char **cpp, **lpp; + const unsigned char *eob, *rmsg; + const unsigned char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) + { + if ((rmsg = *dnptrs++) != NULL) + { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } + else + rmsg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do + { + int l0; + + n = *srcp; + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + { + errno = EMSGSIZE; + return -1; + } + if ((l0 = labellen(srcp)) < 0) + { + errno = EINVAL; + return -1; + } + l += l0 + 1; + if (l > MOWGLI_DNS_NS_MAXCDNAME) + { + errno = EMSGSIZE; + return -1; + } + srcp += l0 + 1; + } + while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do + { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && rmsg != NULL) + { + l = mowgli_dns_dn_find(srcp, rmsg, (const unsigned char *const *)dnptrs, + (const unsigned char *const *)lpp); + if (l >= 0) + { + if (dstp + 1 >= eob) + { + goto cleanup; + } + *dstp++ = (l >> 8) | MOWGLI_DNS_NS_CMPRSFLAGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && (dstp - rmsg) < 0x4000 && first) + { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & MOWGLI_DNS_NS_CMPRSFLAGS) == MOWGLI_DNS_NS_CMPRSFLAGS) + { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) + { + goto cleanup; + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } + while (n != 0); + + if (dstp > eob) + { + cleanup: + if (rmsg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return -1; + } + return (dstp - dst); +} + +static int +mowgli_dns_ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, + unsigned char **dnptrs, unsigned char **lastdnptr) +{ + unsigned char tmp[MOWGLI_DNS_NS_MAXCDNAME]; + + if (mowgli_dns_ns_name_pton(src, tmp, sizeof tmp) == -1) + return -1; + return (mowgli_dns_ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +static int +mowgli_dns_encode_bitsring(const char **bp, const char *end, unsigned char **labelp, + unsigned char **dst, const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + char *tp, c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return EINVAL; + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return EINVAL; + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return EINVAL; + + for (tp = (char *)(dst + 1); cp < end && tp < eom; cp++) + { + switch ((c = *cp)) + { + case ']': /* end of the bitstring */ + if (afterslash) + { + if (beg_blen == NULL) + return EINVAL; + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return EINVAL; + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) + { + if (!isdigit(c & 0xff)) + return EINVAL; + if (beg_blen == NULL) + { + + if (c == '0') + { + /* blen never begings with 0 */ + return EINVAL; + } + beg_blen = cp; + } + } + else + { + if (!isxdigit(c & 0xff)) + return EINVAL; + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return EINVAL; + if (count == 8) + { + *tp++ = value; + count = 0; + } + } + break; + } + } + done: + if (cp >= end || tp >= eom) + return (EMSGSIZE); + + /* + * bit length validation: + * If a <length> is present, the number of digits in the <bit-data> + * MUST be just sufficient to contain the number of bits specified + * by the <length>. If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) + { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return EINVAL; + traillen = tbcount - blen; /* between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return EINVAL; + } + else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = MOWGLI_DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = (unsigned char *)tp; + + return 0; +} + +/* + * dn_find(domain, rmsg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from rmsg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +mowgli_dns_dn_find(const unsigned char *domain, const unsigned char *rmsg, + const unsigned char *const *dnptrs, const unsigned char *const *lastdnptr) +{ + const unsigned char *dn, *cp, *sp; + const unsigned char *const *cpp; + unsigned int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) + { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & MOWGLI_DNS_NS_CMPRSFLAGS) == 0 && (sp - rmsg) < 0x4000) + { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) + { + /* + * check for indirection + */ + switch (n & MOWGLI_DNS_NS_CMPRSFLAGS) + { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for ( ; n > 0; n--) + if (mowgli_dns_mklower(*dn++) != mowgli_dns_mklower(*cp++)) + goto next; + + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return sp - rmsg; + if (*dn) + continue; + goto next; + case MOWGLI_DNS_NS_CMPRSFLAGS: /* indirection */ + cp = rmsg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return -1; + } + } + next:; + sp += *sp + 1; + } + } + errno = ENOENT; + return -1; +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int mowgli_dns_mklower(int ch) +{ + if (ch >= 0x41 && ch <= 0x5A) + return ch + 0x20; + + return ch; +} + +/* From resolv/mkquery.c */ + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int mowgli_dns_res_mkquery(const char *dname, /* domain name */ + int query_class, int type, /* class and type of query */ + unsigned char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + mowgli_dns_resheader_t *hp; + unsigned char *cp; + int n; + unsigned char *dnptrs[20], **dpp, **lastdnptr; + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < MOWGLI_DNS_HFIXEDSIZE)) + return -1; + memset(buf, 0, MOWGLI_DNS_HFIXEDSIZE); + hp = (mowgli_dns_resheader_t *) buf; + + hp->id = 0; + hp->opcode = MOWGLI_DNS_QUERY; + hp->rd = 1; /* recurse */ + hp->rcode = MOWGLI_DNS_NO_ERRORS; + cp = buf + MOWGLI_DNS_HFIXEDSIZE; + buflen -= MOWGLI_DNS_HFIXEDSIZE; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + if ((buflen -= MOWGLI_DNS_QFIXEDSIZE) < 0) + return -1; + if ((n = mowgli_dns_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return -1; + + cp += n; + buflen -= n; + MOWGLI_DNS_NS_PUT16(type, cp); + MOWGLI_DNS_NS_PUT16(query_class, cp); + hp->qdcount = htons(1); + + return cp - buf; +} diff --git a/src/libmowgli/dns/dns_evloop_reslib.h b/src/libmowgli/dns/dns_evloop_reslib.h new file mode 100644 index 0000000..b6fcf03 --- /dev/null +++ b/src/libmowgli/dns/dns_evloop_reslib.h @@ -0,0 +1,112 @@ +/* + * dns/reslib.h + * + * $Id: reslib.h 446 2006-02-12 02:46:54Z db $ + */ + +#ifndef __MOWGLI_DNS_RESLIB_H__ +#define __MOWGLI_DNS_RESLIB_H__ + +/* Here we define some values lifted from nameser.h */ +#define MOWGLI_DNS_NS_NOTIFY_OP 4 +#define MOWGLI_DNS_NS_INT16SIZE 2 +#define MOWGLI_DNS_NS_IN6ADDRSIZE 16 +#define MOWGLI_DNS_NS_INADDRSIZE 4 +#define MOWGLI_DNS_NS_INT32SIZE 4 +#define MOWGLI_DNS_NS_CMPRSFLAGS 0xc0 +#define MOWGLI_DNS_NS_MAXCDNAME 255 +#define MOWGLI_DNS_QUERY 0 +#define MOWGLI_DNS_IQUERY 1 +#define MOWGLI_DNS_NO_ERRORS 0 +#define MOWGLI_DNS_SERVFAIL 2 +#define MOWGLI_DNS_NXDOMAIN 3 +#define MOWGLI_DNS_C_IN 1 +#define MOWGLI_DNS_QFIXEDSIZE 4 +#define MOWGLI_DNS_RRFIXEDSIZE 10 +#define MOWGLI_DNS_HFIXEDSIZE 12 + +typedef struct +{ + unsigned id:16; /* query identification number */ +#ifdef WORDS_BIGENDIAN + /* fields in third byte */ + unsigned qr:1; /* response flag */ + unsigned opcode:4; /* purpose of message */ + unsigned aa:1; /* authoritive answer */ + unsigned tc:1; /* truncated message */ + unsigned rd:1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra:1; /* recursion available */ + unsigned unused:1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad:1; /* authentic data from named */ + unsigned cd:1; /* checking disabled by resolver */ + unsigned rcode:4; /* response code */ +#else + /* fields in third byte */ + unsigned rd:1; /* recursion desired */ + unsigned tc:1; /* truncated message */ + unsigned aa:1; /* authoritive answer */ + unsigned opcode:4; /* purpose of message */ + unsigned qr:1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode:4; /* response code */ + unsigned cd:1; /* checking disabled by resolver */ + unsigned ad:1; /* authentic data from named */ + unsigned unused:1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra:1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount:16; /* number of question entries */ + unsigned ancount:16; /* number of answer entries */ + unsigned nscount:16; /* number of authority entries */ + unsigned arcount:16; /* number of resource entries */ +} mowgli_dns_resheader_t; + +/* + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define MOWGLI_DNS_NS_GET16(s, cp) { \ + const unsigned char *t_cp = (const unsigned char *)(cp); \ + (s) = ((uint16_t)t_cp[0] << 8) \ + | ((uint16_t)t_cp[1]) \ + ; \ + (cp) += MOWGLI_DNS_NS_INT16SIZE; \ +} + +#define MOWGLI_DNS_NS_GET32(l, cp) { \ + const unsigned char *t_cp = (const unsigned char *)(cp); \ + (l) = ((uint32_t)t_cp[0] << 24) \ + | ((uint32_t)t_cp[1] << 16) \ + | ((uint32_t)t_cp[2] << 8) \ + | ((uint32_t)t_cp[3]) \ + ; \ + (cp) += MOWGLI_DNS_NS_INT32SIZE; \ +} + +#define MOWGLI_DNS_NS_PUT16(s, cp) { \ + uint16_t t_s = (uint16_t)(s); \ + unsigned char *t_cp = (unsigned char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += MOWGLI_DNS_NS_INT16SIZE; \ +} + +#define MOWGLI_DNS_NS_PUT32(l, cp) { \ + uint32_t t_l = (uint32_t)(l); \ + unsigned char *t_cp = (unsigned char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += MOWGLI_DNS_NS_INT32SIZE; \ +} + +extern int mowgli_dns_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz); +extern int mowgli_dns_dn_skipname(const unsigned char *ptr, const unsigned char *eom); +extern unsigned int mowgli_dns_ns_get16(const unsigned char *src); +extern unsigned long mowgli_dns_ns_get32(const unsigned char *src); +extern void mowgli_dns_ns_put16(unsigned int src, unsigned char *dst); +extern void mowgli_dns_ns_put32(unsigned long src, unsigned char *dst); +extern int mowgli_dns_res_mkquery(const char *dname, int query_class, int type, unsigned char *buf, int buflen); + +#endif diff --git a/src/libmowgli/dns/dns_evloop_reslist_win32.c b/src/libmowgli/dns/dns_evloop_reslist_win32.c new file mode 100644 index 0000000..eb45ce8 --- /dev/null +++ b/src/libmowgli/dns/dns_evloop_reslist_win32.c @@ -0,0 +1,97 @@ +/* + * reslist.c - get nameservers from windows * + * + * Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2008 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#ifdef _WIN32 +#include "mowgli.h" +#include <windows.h> +#include <iphlpapi.h> + +int +mowgli_dns_get_windows_nameservers(char *ret_buf, size_t ret_size) +{ + FIXED_INFO *fixedinfo, tfixedinfo; + DWORD size = sizeof(*fixedinfo); + typedef DWORD(WINAPI * get_net_param_func) (FIXED_INFO *, DWORD *); + get_net_param_func get_network_params; + HMODULE handle; + IP_ADDR_STRING *ip_addr; + int i, count = 0; + size_t ip_size = sizeof("255.255.255.255"); + size_t left = ret_size; + char *ret = ret_buf; + HRESULT res; + + if (!(handle = LoadLibrary("iphlpapi.dll"))) + return 0; + + if (!(get_network_params = (get_net_param_func)GetProcAddress(handle, "GetNetworkParams"))) + goto quit; + + res = (*get_network_params)(&tfixedinfo, &size); + if((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) + goto quit; + + fixedinfo = mowgli_alloc(size); + if(!fixedinfo || (*get_network_params)(fixedinfo, &size) != ERROR_SUCCESS) + goto quit; + +#ifdef DEBUG + mowgli_log("Host Name: %s\n", fixedinfo->HostName); + mowgli_log("Domain Name: %s\n", fixedinfo->DomainName); + mowgli_log("DNS Servers:\n\t%s (primary)\n", fixedinfo->DnsServerList.IpAddress.String); +#endif + + if(strlen(fixedinfo->DnsServerList.IpAddress.String) > 0 && + inet_addr(fixedinfo->DnsServerList.IpAddress.String) != INADDR_NONE && left > ip_size) + { + ret += sprintf(ret, "%s,", fixedinfo->DnsServerList.IpAddress.String); + left -= ret - ret_buf; + count++; + } + + for(i = 0, ip_addr = fixedinfo->DnsServerList.Next; ip_addr && left > ip_size; ip_addr = ip_addr->Next, i++) + { + if(inet_addr(ip_addr->IpAddress.String) != INADDR_NONE) + { + ret += sprintf(ret, "%s,", ip_addr->IpAddress.String); + left -= ret - ret_buf; + count++; + } +#ifdef DEBUG + mowgli_log("\t%s (secondary %d)\n", ip_addr->IpAddress.String, i + 1); +#endif + } + + mowgli_free(fixedinfo); + +quit: + if(handle) + FreeLibrary(handle); + + if(left <= ip_size) + mowgli_log("Too many nameservers. Truncating to %d addressess", count); + + if(ret > ret_buf) + ret[-1] = '\0'; + + return count; +} + +#endif + diff --git a/src/libmowgli/eventloop/Makefile b/src/libmowgli/eventloop/Makefile new file mode 100644 index 0000000..23122a1 --- /dev/null +++ b/src/libmowgli/eventloop/Makefile @@ -0,0 +1,14 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_EVENTLOOP} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_EVENTLOOP} + +SRCS = eventloop.c helper.c pollable.c timer.c null_pollops.c poll_pollops.c epoll_pollops.c kqueue_pollops.c qnx_pollops.c ports_pollops.c select_pollops.c windows_pollops.c + +INCLUDES = eventloop.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/eventloop + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE diff --git a/src/libmowgli/eventloop/epoll_pollops.c b/src/libmowgli/eventloop/epoll_pollops.c new file mode 100644 index 0000000..596b992 --- /dev/null +++ b/src/libmowgli/eventloop/epoll_pollops.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_SYS_EPOLL_H + +#include <sys/epoll.h> + +typedef struct { + int epoll_fd; + int pfd_size; + struct epoll_event *pfd; +} mowgli_epoll_eventloop_private_t; + +static void mowgli_epoll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_epoll_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_epoll_eventloop_private_t)); + eventloop->poller = priv; + + priv->pfd_size = getdtablesize(); + priv->epoll_fd = epoll_create(priv->pfd_size); + priv->pfd = mowgli_alloc(sizeof(struct epoll_event) * priv->pfd_size); + + return; +} + +static void mowgli_epoll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_epoll_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + close(priv->epoll_fd); + + mowgli_free(priv->pfd); + mowgli_free(priv); + return; +} + +static void mowgli_epoll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_epoll_eventloop_private_t *priv; + struct epoll_event ep_event; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + pollable->slot = 0; + + ep_event.events = pollable->slot; + ep_event.data.ptr = pollable; + + if (epoll_ctl(priv->epoll_fd, EPOLL_CTL_DEL, pollable->fd, &ep_event) != 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_epoll_eventloop_destroy(): epoll_ctl failed: %d (%s)", errno, strerror(errno)); + } +} + +static void mowgli_epoll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_epoll_eventloop_private_t *priv; + struct epoll_event ep_event; + int op = -1; + unsigned int old_flags; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + old_flags = pollable->slot; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + pollable->slot |= EPOLLIN; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + pollable->slot |= EPOLLOUT; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function == NULL) + pollable->slot &= ~EPOLLIN; + + if (pollable->write_function == NULL) + pollable->slot &= ~EPOLLOUT; + + if (old_flags == 0 && pollable->slot == 0) + return; + else if (pollable->slot <= 0) + op = EPOLL_CTL_DEL; + else if (old_flags == 0 && pollable->slot != 0) + op = EPOLL_CTL_ADD; + else if (pollable->slot != old_flags) + op = EPOLL_CTL_MOD; + + if (op == -1) + return; + + ep_event.events = pollable->slot; + ep_event.data.ptr = pollable; + + if (epoll_ctl(priv->epoll_fd, op, pollable->fd, &ep_event) != 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_epoll_eventloop_setselect(): epoll_ctl failed: %d (%s)", errno, strerror(errno)); + } + + return; +} + +static void mowgli_epoll_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_epoll_eventloop_private_t *priv; + int i, num, o_errno; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + num = epoll_wait(priv->epoll_fd, priv->pfd, priv->pfd_size, delay); + + o_errno = errno; + mowgli_eventloop_synchronize(eventloop); + + if (num < 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_epoll_eventloop_select(): epoll_wait failed: %d (%s)", o_errno, strerror(o_errno)); + return; + } + + for (i = 0; i < num; i++) + { + mowgli_eventloop_pollable_t *pollable = priv->pfd[i].data.ptr; + + if (priv->pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR) && pollable->read_function != NULL) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (priv->pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR) && pollable->write_function != NULL) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } +} + +mowgli_eventloop_ops_t _mowgli_epoll_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_epoll_eventloop_pollsetup, + .pollshutdown = mowgli_epoll_eventloop_pollshutdown, + .setselect = mowgli_epoll_eventloop_setselect, + .select = mowgli_epoll_eventloop_select, + .destroy = mowgli_epoll_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/eventloop.c b/src/libmowgli/eventloop/eventloop.c new file mode 100644 index 0000000..d2045cd --- /dev/null +++ b/src/libmowgli/eventloop/eventloop.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *eventloop_heap = NULL; + +extern mowgli_eventloop_ops_t _mowgli_null_pollops; + +#ifdef HAVE_PORT_CREATE +extern mowgli_eventloop_ops_t _mowgli_ports_pollops; +#endif +#ifdef HAVE_DISPATCH_BLOCK +extern mowgli_eventloop_ops_t _mowgli_qnx_pollops; +#endif +#ifdef HAVE_SELECT +extern mowgli_eventloop_ops_t _mowgli_select_pollops; +#endif +#ifdef HAVE_POLL_H +extern mowgli_eventloop_ops_t _mowgli_poll_pollops; +#endif +#ifdef HAVE_SYS_EPOLL_H +extern mowgli_eventloop_ops_t _mowgli_epoll_pollops; +#endif +#ifdef HAVE_KQUEUE +extern mowgli_eventloop_ops_t _mowgli_kqueue_pollops; +#endif +#if 0 +extern mowgli_eventloop_ops_t _mowgli_winsock_pollops; +#endif + +mowgli_eventloop_t *mowgli_eventloop_create(void) +{ + mowgli_eventloop_t *eventloop; + + if (eventloop_heap == NULL) + eventloop_heap = mowgli_heap_create(sizeof(mowgli_eventloop_t), 16, BH_NOW); + + eventloop = mowgli_heap_alloc(eventloop_heap); + + eventloop->eventloop_ops = &_mowgli_null_pollops; + +#ifdef HAVE_SELECT + eventloop->eventloop_ops = &_mowgli_select_pollops; +#endif +#ifdef HAVE_POLL_H + eventloop->eventloop_ops = &_mowgli_poll_pollops; +#endif +#ifdef HAVE_SYS_EPOLL_H + eventloop->eventloop_ops = &_mowgli_epoll_pollops; +#endif +#ifdef HAVE_KQUEUE + eventloop->eventloop_ops = &_mowgli_kqueue_pollops; +#endif +#ifdef HAVE_DISPATCH_BLOCK + eventloop->eventloop_ops = &_mowgli_qnx_pollops; +#endif +#ifdef HAVE_PORT_CREATE + eventloop->eventloop_ops = &_mowgli_ports_pollops; +#endif +#if 0 + eventloop->eventloop_ops = &_mowgli_winsock_pollops; +#endif + + if (mowgli_mutex_init(&eventloop->mutex) != 0) + { + mowgli_log("couldn't create mutex for eventloop %p, aborting...", eventloop); + abort(); + } + + eventloop->eventloop_ops->pollsetup(eventloop); + + mowgli_eventloop_synchronize(eventloop); + + return eventloop; +} + +void mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop) +{ + eventloop->eventloop_ops->pollshutdown(eventloop); + + mowgli_mutex_uninit(&eventloop->mutex); + mowgli_heap_free(eventloop_heap, eventloop); +} + +void mowgli_eventloop_run(mowgli_eventloop_t *eventloop) +{ + return_if_fail(eventloop != NULL); + + mowgli_mutex_lock(&eventloop->mutex); + + eventloop->death_requested = false; + + while (!eventloop->death_requested) + eventloop->eventloop_ops->run_once(eventloop); + + mowgli_mutex_unlock(&eventloop->mutex); +} + +void mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop) +{ + return_if_fail(eventloop != NULL); + + mowgli_mutex_lock(&eventloop->mutex); + + eventloop->eventloop_ops->run_once(eventloop); + + mowgli_mutex_unlock(&eventloop->mutex); +} + +void mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) +{ + return_if_fail(eventloop != NULL); + + mowgli_mutex_lock(&eventloop->mutex); + + if (timeout >= 0) + eventloop->eventloop_ops->timeout_once(eventloop, timeout); + else + eventloop->eventloop_ops->run_once(eventloop); + + mowgli_mutex_unlock(&eventloop->mutex); +} + +void mowgli_eventloop_break(mowgli_eventloop_t *eventloop) +{ + return_if_fail(eventloop != NULL); + + eventloop->death_requested = true; +} + +/* convenience function to request null pollops */ +void mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop) +{ + return_if_fail(eventloop != NULL); + + eventloop->eventloop_ops = &_mowgli_null_pollops; +} + +/* userdata setting/getting functions (for bindings) */ +void *mowgli_eventloop_get_data(mowgli_eventloop_t *eventloop) +{ + return_val_if_fail(eventloop != NULL, NULL); + + return eventloop->data; +} + +void mowgli_eventloop_set_data(mowgli_eventloop_t *eventloop, void *data) +{ + return_if_fail(eventloop != NULL); + + eventloop->data = data; +} diff --git a/src/libmowgli/eventloop/eventloop.h b/src/libmowgli/eventloop/eventloop.h new file mode 100644 index 0000000..4c07b27 --- /dev/null +++ b/src/libmowgli/eventloop/eventloop.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2011, 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_EVENTLOOP_EVENTLOOP_H__ +#define __MOWGLI_EVENTLOOP_EVENTLOOP_H__ + +#ifndef _WIN32 + +typedef int mowgli_descriptor_t; + +#else + +typedef SOCKET mowgli_descriptor_t; + +#endif + +typedef enum { + MOWGLI_EVENTLOOP_TYPE_POLLABLE, + MOWGLI_EVENTLOOP_TYPE_HELPER, + MOWGLI_EVENTLOOP_TYPE_ERROR = -1 +} mowgli_eventloop_io_type_t; + +typedef struct { + mowgli_eventloop_io_type_t type; +} mowgli_eventloop_io_obj_t; + +typedef struct _mowgli_eventloop mowgli_eventloop_t; + +typedef struct _mowgli_pollable mowgli_eventloop_pollable_t; +typedef struct _mowgli_helper mowgli_eventloop_helper_proc_t; + +typedef struct _mowgli_linebuf mowgli_linebuf_t; + +typedef enum { + MOWGLI_EVENTLOOP_IO_READ, + MOWGLI_EVENTLOOP_IO_WRITE, + MOWGLI_EVENTLOOP_IO_ERROR = -1 +} mowgli_eventloop_io_dir_t; + +typedef void mowgli_eventloop_io_t; + +/* checked casts */ +static inline mowgli_eventloop_pollable_t *mowgli_eventloop_io_pollable(mowgli_eventloop_io_t *io) +{ + mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; + + return_val_if_fail(io != NULL, NULL); + return_val_if_fail(obj->type == MOWGLI_EVENTLOOP_TYPE_POLLABLE, NULL); + + return (mowgli_eventloop_pollable_t *) io; +} + +static inline mowgli_eventloop_helper_proc_t *mowgli_eventloop_io_helper(mowgli_eventloop_io_t *io) +{ + mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; + + return_val_if_fail(io != NULL, NULL); + return_val_if_fail(obj->type == MOWGLI_EVENTLOOP_TYPE_HELPER, NULL); + + return (mowgli_eventloop_helper_proc_t *) io; +} + +static inline mowgli_eventloop_io_type_t mowgli_eventloop_io_type(mowgli_eventloop_io_t *io) +{ + mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io; + + return_val_if_fail(io != NULL, MOWGLI_EVENTLOOP_TYPE_ERROR); + + return obj->type; +} + +typedef void mowgli_eventloop_io_cb_t(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); + +struct _mowgli_pollable { + mowgli_eventloop_io_obj_t type; + + mowgli_descriptor_t fd; + unsigned int slot; + unsigned int events; + + mowgli_eventloop_io_cb_t *read_function; + mowgli_eventloop_io_cb_t *write_function; + mowgli_eventloop_io_cb_t *error_function; + + void *userdata; + + mowgli_node_t node; + + mowgli_eventloop_t *eventloop; +}; + +typedef struct { + void (*timeout_once)(mowgli_eventloop_t *eventloop, int timeout); + void (*run_once)(mowgli_eventloop_t *eventloop); + void (*pollsetup)(mowgli_eventloop_t *eventloop); + void (*pollshutdown)(mowgli_eventloop_t *eventloop); + void (*setselect)(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function); + void (*select)(mowgli_eventloop_t *eventloop, int time); + void (*destroy)(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable); +} mowgli_eventloop_ops_t; + +struct _mowgli_eventloop { + time_t currtime; + time_t deadline; + + const char *last_ran; + + mowgli_list_t timer_list; + mowgli_mutex_t mutex; + + mowgli_eventloop_ops_t *eventloop_ops; + void *poller; + + bool death_requested; + + void *data; +}; + +typedef void mowgli_event_dispatch_func_t(void *userdata); + +typedef struct { + mowgli_node_t node; + + mowgli_event_dispatch_func_t *func; + void *arg; + const char *name; + time_t frequency; + time_t when; + bool active; +} mowgli_eventloop_timer_t; + +static inline void mowgli_eventloop_set_time(mowgli_eventloop_t *eventloop, time_t newtime) +{ + return_if_fail(eventloop != NULL); + + eventloop->currtime = newtime; +} + +static inline time_t mowgli_eventloop_get_time(mowgli_eventloop_t *eventloop) +{ + return_val_if_fail(eventloop != NULL, 0); + + return eventloop->currtime; +} + +static inline void mowgli_eventloop_synchronize(mowgli_eventloop_t *eventloop) +{ + mowgli_eventloop_set_time(eventloop, time(NULL)); +} + +static inline bool mowgli_eventloop_ignore_errno(int error) +{ + switch (error) + { +#ifdef EINPROGRESS + case EINPROGRESS: +#endif +#if defined(EWOULDBLOCK) + case EWOULDBLOCK: +#endif +#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN) + case EAGAIN: +#endif +#ifdef EINTR + case EINTR: +#endif +#ifdef ERESTART + case ERESTART: +#endif +#ifdef ENOBUFS + case ENOBUFS: +#endif +#ifdef ENOENT + case ENOENT: +#endif + return true; + default: + break; + } + + return false; +} + +typedef void mowgli_eventloop_helper_start_fn_t(mowgli_eventloop_helper_proc_t *helper, void *userdata); + +struct _mowgli_helper { + mowgli_eventloop_io_obj_t type; + + mowgli_process_t *child; + mowgli_eventloop_t *eventloop; + + mowgli_descriptor_t fd; + mowgli_eventloop_pollable_t *pfd; + + mowgli_eventloop_io_cb_t *read_function; + + void *userdata; +}; + +/* helper.c */ +extern mowgli_eventloop_helper_proc_t *mowgli_helper_create(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_start_fn_t *start_fn, const char *helpername, void *userdata); + +/* creation of helpers inside other executable images */ +extern mowgli_eventloop_helper_proc_t *mowgli_helper_spawn(mowgli_eventloop_t *eventloop, const char *path, char *const argv[]); +extern mowgli_eventloop_helper_proc_t *mowgli_helper_setup(mowgli_eventloop_t *eventloop); + +/* synchronization of helpers happens on reading from mowgli_eventloop_helper_proc_t::in_pfd. */ +extern void mowgli_helper_set_read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper, mowgli_eventloop_io_cb_t *read_fn); +extern void mowgli_helper_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper); + +/* null_pollops.c */ +extern void mowgli_simple_eventloop_run_once(mowgli_eventloop_t *eventloop); +extern void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout); +extern void mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); + +/* eventloop.c */ +extern mowgli_eventloop_t *mowgli_eventloop_create(void); +extern void mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop); +extern void mowgli_eventloop_run(mowgli_eventloop_t *eventloop); +extern void mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop); +extern void mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout); +extern void mowgli_eventloop_break(mowgli_eventloop_t *eventloop); +extern void mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop); +extern void mowgli_eventloop_set_data(mowgli_eventloop_t *eventloop, void *data); +extern void *mowgli_eventloop_get_data(mowgli_eventloop_t *eventloop); + +/* timer.c */ +extern mowgli_eventloop_timer_t *mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when); +extern mowgli_eventloop_timer_t *mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when); +extern void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer); +extern void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop); +extern time_t mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop); +extern mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg); + +/* pollable.c */ +extern mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *eventloop, mowgli_descriptor_t fd, void *userdata); +extern void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable); +extern void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function); +extern void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking); + +#endif + diff --git a/src/libmowgli/eventloop/helper.c b/src/libmowgli/eventloop/helper.c new file mode 100644 index 0000000..b89e447 --- /dev/null +++ b/src/libmowgli/eventloop/helper.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +typedef struct { + mowgli_eventloop_helper_start_fn_t *start_fn; + void *userdata; + mowgli_descriptor_t fd; +} mowgli_helper_create_req_t; + +static void +mowgli_helper_trampoline(mowgli_helper_create_req_t *req) +{ + mowgli_eventloop_helper_proc_t *helper; +#ifndef _WIN32 + int i, x; +#endif + + return_if_fail(req != NULL); + return_if_fail(req->start_fn != NULL); + + helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); + helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; + helper->fd = req->fd; + +#ifndef _WIN32 + for (i = 0; i < 1024; i++) + { + if (i != req->fd) + close(i); + } + + x = open("/dev/null", O_RDWR); + + for (i = 0; i < 2; i++) + { + if (req->fd != i) + dup2(x, i); + } + + if (x > 2) + close(x); +#endif + + helper->eventloop = mowgli_eventloop_create(); + helper->pfd = mowgli_pollable_create(helper->eventloop, helper->fd, helper); + helper->userdata = req->userdata; + + mowgli_pollable_set_nonblocking(helper->pfd, true); + + req->start_fn(helper, helper->userdata); +} + +mowgli_eventloop_helper_proc_t * +mowgli_helper_create(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_start_fn_t *start_fn, const char *helpername, void *userdata) +{ + mowgli_eventloop_helper_proc_t *helper; + mowgli_helper_create_req_t child; + int io_fd[2]; + + return_val_if_fail(eventloop != NULL, NULL); + return_val_if_fail(start_fn != NULL, NULL); + + child.start_fn = start_fn; + child.userdata = userdata; + + helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); + helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; + helper->eventloop = eventloop; + + socketpair(AF_UNIX, SOCK_STREAM, 0, io_fd); + + /* set up helper/child fd mapping */ + helper->fd = io_fd[0]; + child.fd = io_fd[1]; + + /* make pollables and make them non-blocking */ + helper->pfd = mowgli_pollable_create(eventloop, helper->fd, helper); + mowgli_pollable_set_nonblocking(helper->pfd, true); + + /* spawn helper process using mowgli_process_clone() */ + helper->child = mowgli_process_clone((mowgli_process_start_fn_t) mowgli_helper_trampoline, helpername, &child); + + if (helper->child == NULL) + { + mowgli_pollable_destroy(eventloop, helper->pfd); + + close(io_fd[0]); + close(io_fd[1]); + + mowgli_free(helper); + return NULL; + } + + close(child.fd); + + return helper; +} + +mowgli_eventloop_helper_proc_t * +mowgli_helper_spawn(mowgli_eventloop_t *eventloop, const char *path, char *const argv[]) +{ + mowgli_eventloop_helper_proc_t *helper; + int io_fd[2]; + char buf[64]; + + return_val_if_fail(eventloop != NULL, NULL); + return_val_if_fail(path != NULL, NULL); + + helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); + helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; + helper->eventloop = eventloop; + + socketpair(AF_UNIX, SOCK_STREAM, 0, io_fd); + + /* set up helper/child fd mapping */ + helper->fd = io_fd[0]; + + /* make pollables and make them non-blocking */ + helper->pfd = mowgli_pollable_create(eventloop, helper->fd, helper); + + snprintf(buf, sizeof buf, "%d", io_fd[1]); + setenv("IO_FD", buf, 1); + + /* Spawn helper process using mowgli_process_spawn(), helper will get + * IO_FD mapping from getenv(). Ugly hack, but it works... + * --nenolod + */ + helper->child = mowgli_process_spawn(path, argv); + + if (helper->child == NULL) + { + mowgli_pollable_destroy(eventloop, helper->pfd); + + close(io_fd[0]); + close(io_fd[1]); + + mowgli_free(helper); + return NULL; + } + + close(io_fd[1]); + + return helper; +} + +/* Set up a helper connection to parent using getenv() */ +mowgli_eventloop_helper_proc_t * +mowgli_helper_setup(mowgli_eventloop_t *eventloop) +{ + mowgli_eventloop_helper_proc_t *helper; + const char *env_io_fd; + + env_io_fd = getenv("IO_FD"); + + /* this shouldn't be a hard-fail because some idiot may run the helper from + * the cmdline. allow the helper to error out gracefully if not spawned as + * a helper. + */ + if (env_io_fd == NULL) + return NULL; + + helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); + helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; + helper->eventloop = eventloop; + helper->fd = atoi(env_io_fd); + helper->pfd = mowgli_pollable_create(helper->eventloop, helper->fd, helper); + + mowgli_pollable_set_nonblocking(helper->pfd, true); + + return helper; +} + +static void +mowgli_helper_io_trampoline(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_eventloop_helper_proc_t *helper = userdata; + + switch (dir) { + case MOWGLI_EVENTLOOP_IO_READ: + if (helper->read_function != NULL) + return helper->read_function(eventloop, helper, MOWGLI_EVENTLOOP_IO_READ, helper->userdata); + default: + break; + } +} + +void +mowgli_helper_set_read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper, mowgli_eventloop_io_cb_t *read_fn) +{ + return_if_fail(eventloop != NULL); + return_if_fail(helper != NULL); + + if (read_fn == NULL) + mowgli_pollable_setselect(eventloop, helper->pfd, MOWGLI_EVENTLOOP_IO_READ, NULL); + + helper->read_function = read_fn; + mowgli_pollable_setselect(eventloop, helper->pfd, MOWGLI_EVENTLOOP_IO_READ, mowgli_helper_io_trampoline); +} + +void +mowgli_helper_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper) +{ + return_if_fail(eventloop != NULL); + return_if_fail(helper != NULL); + + mowgli_process_kill(helper->child); + mowgli_pollable_destroy(eventloop, helper->pfd); + close(helper->fd); + + mowgli_free(helper); +} diff --git a/src/libmowgli/eventloop/kqueue_pollops.c b/src/libmowgli/eventloop/kqueue_pollops.c new file mode 100644 index 0000000..7bfa2bb --- /dev/null +++ b/src/libmowgli/eventloop/kqueue_pollops.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * Copyright (c) 2011 Jilles Tjoelker <jilles@stack.nl>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_KQUEUE + +#include <sys/event.h> + +typedef struct { + int kqueue_fd; + int nevents; + struct kevent *events; +} mowgli_kqueue_eventloop_private_t; + +static void mowgli_kqueue_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_kqueue_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_kqueue_eventloop_private_t)); + eventloop->poller = priv; + + priv->nevents = getdtablesize(); + priv->kqueue_fd = kqueue(); + priv->events = mowgli_alloc(sizeof(struct kevent) * priv->nevents); + + return; +} + +static void mowgli_kqueue_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_kqueue_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + close(priv->kqueue_fd); + + mowgli_free(priv->events); + mowgli_free(priv); + return; +} + +static void mowgli_kqueue_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_kqueue_eventloop_private_t *priv; + struct kevent event; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + EV_SET(&event, pollable->fd, EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, pollable); + if (kevent(priv->kqueue_fd, &event, 1, NULL, 0, + &(const struct timespec){ .tv_sec = 0, .tv_nsec = 0} + ) != 0) + { + mowgli_log("mowgli_kqueue_eventloop_setselect(): kevent failed: %d (%s)", errno, strerror(errno)); + } +} + +static void mowgli_kqueue_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_kqueue_eventloop_private_t *priv; + mowgli_eventloop_io_cb_t **fptr; + struct kevent event; + int filter; + bool change; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + change = false; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + fptr = &pollable->read_function; + filter = EVFILT_READ; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + fptr = &pollable->write_function; + filter = EVFILT_WRITE; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + return; + } + + change = (*fptr != NULL) != (event_function != NULL); + + *fptr = event_function; + + if (!change) + return; + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + EV_SET(&event, pollable->fd, filter, + event_function ? EV_ADD : EV_DELETE, 0, 0, pollable); + if (kevent(priv->kqueue_fd, &event, 1, NULL, 0, + &(const struct timespec){ .tv_sec = 0, .tv_nsec = 0} + ) != 0) + { + mowgli_log("mowgli_kqueue_eventloop_setselect(): kevent failed: %d (%s)", errno, strerror(errno)); + } +} + +static void mowgli_kqueue_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_kqueue_eventloop_private_t *priv; + int i, num, o_errno; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + num = kevent(priv->kqueue_fd, NULL, 0, priv->events, priv->nevents, + delay >= 0 ? &(const struct timespec){ .tv_sec = delay / 1000, + .tv_nsec = delay % 1000 * 1000000 } : NULL); + + o_errno = errno; + mowgli_eventloop_synchronize(eventloop); + + if (num < 0) + { + if (mowgli_eventloop_ignore_errno(o_errno)) + return; + + mowgli_log("mowgli_kqueue_eventloop_select(): kevent failed: %d (%s)", o_errno, strerror(o_errno)); + return; + } + + for (i = 0; i < num; i++) + { + mowgli_eventloop_pollable_t *pollable = priv->events[i].udata; + + if (priv->events[i].filter == EVFILT_READ && + pollable->read_function != NULL) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (priv->events[i].filter == EVFILT_WRITE && + pollable->write_function != NULL) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + + /* XXX Perhaps we need to recheck read_function and + * write_function now. + */ + } +} + +mowgli_eventloop_ops_t _mowgli_kqueue_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_kqueue_eventloop_pollsetup, + .pollshutdown = mowgli_kqueue_eventloop_pollshutdown, + .setselect = mowgli_kqueue_eventloop_setselect, + .select = mowgli_kqueue_eventloop_select, + .destroy = mowgli_kqueue_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/null_pollops.c b/src/libmowgli/eventloop/null_pollops.c new file mode 100644 index 0000000..8fcabe4 --- /dev/null +++ b/src/libmowgli/eventloop/null_pollops.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout) +{ + time_t delay, currtime; + int t; + + return_if_fail(eventloop != NULL); + return_if_fail(eventloop->eventloop_ops != NULL); + + mowgli_eventloop_synchronize(eventloop); + + currtime = mowgli_eventloop_get_time(eventloop); + delay = mowgli_eventloop_next_timer(eventloop); + + if (delay <= currtime) + { + mowgli_eventloop_run_timers(eventloop); + mowgli_eventloop_synchronize(eventloop); + + currtime = mowgli_eventloop_get_time(eventloop); + delay = mowgli_eventloop_next_timer(eventloop); + } + + if (timeout) + t = timeout; + else + { + if (delay <= currtime) + t = -1; + else + t = (delay - currtime) * 1000; + } + +#ifdef DEBUG + mowgli_log("delay: %ld, currtime: %ld, select period: %d", delay, currtime, t); +#endif + + eventloop->eventloop_ops->select(eventloop, t); + +} + +void mowgli_simple_eventloop_run_once(mowgli_eventloop_t *eventloop) +{ + eventloop->eventloop_ops->timeout_once(eventloop, 0); +} + +void mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_eventloop_pollable_t *pollable = mowgli_eventloop_io_pollable(io); + + if (pollable != NULL) + mowgli_pollable_destroy(eventloop, pollable); +} + +static void mowgli_null_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + return; +} + +static void mowgli_null_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + return; +} + +static void mowgli_null_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + return; +} + +static void mowgli_null_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_log("null eventloop does not really do polling, events for pollable<%p> will be ignored", pollable); + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + + return; +} + +static void mowgli_null_eventloop_select(mowgli_eventloop_t *eventloop, int time) +{ + usleep(time); +} + +mowgli_eventloop_ops_t _mowgli_null_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_null_eventloop_pollsetup, + .pollshutdown = mowgli_null_eventloop_pollshutdown, + .setselect = mowgli_null_eventloop_setselect, + .select = mowgli_null_eventloop_select, + .destroy = mowgli_null_eventloop_destroy, +}; diff --git a/src/libmowgli/eventloop/poll_pollops.c b/src/libmowgli/eventloop/poll_pollops.c new file mode 100644 index 0000000..0bea454 --- /dev/null +++ b/src/libmowgli/eventloop/poll_pollops.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_POLL_H + +#include <poll.h> + +#ifndef POLLRDNORM +#define POLLRDNORM POLLIN +#endif +#ifndef POLLWRNORM +#define POLLWRNORM POLLOUT +#endif + +typedef struct { + struct pollfd pollfds[FD_SETSIZE]; + nfds_t nfds; + mowgli_list_t pollable_list; +} mowgli_poll_eventloop_private_t; + +static nfds_t update_poll_fds(mowgli_eventloop_t *eventloop) +{ + mowgli_node_t *n, *tn; + mowgli_poll_eventloop_private_t *priv; + nfds_t slot = 0; + + return_val_if_fail(eventloop != NULL, 0); + + priv = eventloop->poller; + + memset(priv->pollfds, '\0', sizeof(priv->pollfds)); + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + mowgli_eventloop_pollable_t *pollable = n->data; + +#ifdef DEBUG + mowgli_log("considering fd %d pollable %p count %d", pollable->fd, pollable, priv->pollable_list.count); +#endif + + if (pollable->read_function || pollable->write_function) + { + priv->pollfds[slot].fd = pollable->fd; + + if (pollable->read_function) + priv->pollfds[slot].events |= POLLRDNORM; + + if (pollable->write_function) + priv->pollfds[slot].events |= POLLWRNORM; + + priv->pollfds[slot].revents = 0; + pollable->slot = slot; + slot++; + } + else + pollable->slot = -1; + } + + return slot; +} + +static void mowgli_poll_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_poll_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_poll_eventloop_private_t)); + eventloop->poller = priv; + + return; +} + +static void mowgli_poll_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_node_t *n, *tn; + mowgli_poll_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + mowgli_node_delete(n, &priv->pollable_list); + } + + mowgli_free(priv); + return; +} + +static void mowgli_poll_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_poll_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + mowgli_node_delete(&pollable->node, &priv->pollable_list); +} + +static void mowgli_poll_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_poll_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + if (pollable->read_function || pollable->write_function) + mowgli_node_delete(&pollable->node, &priv->pollable_list); + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function || pollable->write_function) + mowgli_node_add(pollable, &pollable->node, &priv->pollable_list); + + return; +} + +static void mowgli_poll_eventloop_select(mowgli_eventloop_t *eventloop, int time) +{ + mowgli_node_t *n, *tn; + nfds_t nfds; + mowgli_eventloop_pollable_t *pollable; + mowgli_poll_eventloop_private_t *priv; + int slot; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + nfds = update_poll_fds(eventloop); + + if (poll(priv->pollfds, nfds, time) > 0) + { + mowgli_eventloop_synchronize(eventloop); + + /* iterate twice so we don't touch freed memory if a pollable is destroyed */ + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + pollable = n->data; + slot = pollable->slot; + + if (slot == -1 || priv->pollfds[slot].revents == 0) + continue; + + if (priv->pollfds[slot].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR) && pollable->read_function) + { +#ifdef DEBUG + mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_READ, %p)\n", pollable->read_function, eventloop, pollable, pollable->userdata); +#endif + + priv->pollfds[slot].events &= ~(POLLRDNORM | POLLIN); + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + } + } + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + pollable = n->data; + slot = pollable->slot; + + if (slot == -1 || priv->pollfds[slot].revents == 0) + continue; + + if (priv->pollfds[slot].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR) && pollable->write_function) + { +#ifdef DEBUG + mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_WRITE, %p)\n", pollable->write_function, eventloop, pollable, pollable->userdata); +#endif + + priv->pollfds[slot].events &= ~(POLLWRNORM | POLLOUT); + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } + } + } +} + +mowgli_eventloop_ops_t _mowgli_poll_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_poll_eventloop_pollsetup, + .pollshutdown = mowgli_poll_eventloop_pollshutdown, + .setselect = mowgli_poll_eventloop_setselect, + .select = mowgli_poll_eventloop_select, + .destroy = mowgli_poll_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/pollable.c b/src/libmowgli/eventloop/pollable.c new file mode 100644 index 0000000..e2c2e2a --- /dev/null +++ b/src/libmowgli/eventloop/pollable.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *pollable_heap = NULL; + +mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *eventloop, mowgli_descriptor_t fd, void *userdata) +{ + mowgli_eventloop_pollable_t *pollable; + + return_val_if_fail(eventloop != NULL, NULL); + + if (pollable_heap == NULL) + pollable_heap = mowgli_heap_create(sizeof(mowgli_eventloop_pollable_t), 16, BH_NOW); + + pollable = mowgli_heap_alloc(pollable_heap); + + pollable->eventloop = eventloop; + pollable->type.type = MOWGLI_EVENTLOOP_TYPE_POLLABLE; + pollable->fd = fd; + pollable->userdata = userdata; + + return pollable; +} + +void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + /* unregister any interest in the pollable. */ + eventloop->eventloop_ops->destroy(eventloop, pollable); + + mowgli_heap_free(pollable_heap, pollable); +} + +void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + return_if_fail(eventloop->eventloop_ops != NULL); + + eventloop->eventloop_ops->setselect(eventloop, pollable, dir, event_function); +} + +void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking) +{ +#if defined(HAVE_FCNTL) + unsigned long flags; + + return_if_fail(pollable != NULL); + + flags = fcntl(pollable->fd, F_GETFL); + + if (nonblocking) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + + fcntl(pollable->fd, F_SETFL, flags); +#elif defined(HAVE_WINSOCK2_H) + u_long mode; + + return_if_fail(pollable != NULL); + + mode = nonblocking; + + ioctlsocket(pollable->fd, FIONBIO, &mode); +#endif +} diff --git a/src/libmowgli/eventloop/ports_pollops.c b/src/libmowgli/eventloop/ports_pollops.c new file mode 100644 index 0000000..bc838da --- /dev/null +++ b/src/libmowgli/eventloop/ports_pollops.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_PORT_CREATE + +#include <port.h> + +typedef struct { + int port_fd; + int pfd_size; + port_event_t *pfd; +} mowgli_ports_eventloop_private_t; + +static void mowgli_ports_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_ports_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_ports_eventloop_private_t)); + eventloop->poller = priv; + + priv->pfd_size = getdtablesize(); + priv->port_fd = port_create(); + priv->pfd = mowgli_alloc(sizeof(port_event_t) * priv->pfd_size); + + return; +} + +static void mowgli_ports_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_ports_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + close(priv->port_fd); + + mowgli_free(priv->pfd); + mowgli_free(priv); + return; +} + +static void mowgli_ports_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_ports_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + pollable->slot = 0; + + if (port_dissociate(priv->port_fd, PORT_SOURCE_FD, (uintptr_t) pollable->fd) < 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_ports_eventloop_destroy(): port_dissociate failed: %d (%s)", errno, strerror(errno)); + } +} + +static void mowgli_ports_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_ports_eventloop_private_t *priv; + unsigned int old_flags; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + old_flags = pollable->slot; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + pollable->slot |= POLLIN; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + pollable->slot |= POLLOUT; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function == NULL) + pollable->slot &= ~POLLIN; + + if (pollable->write_function == NULL) + pollable->slot &= ~POLLOUT; + + if (old_flags == 0 && pollable->slot == 0) + return; + else if (pollable->slot == 0) + { + port_dissociate(priv->port_fd, PORT_SOURCE_FD, (uintptr_t) pollable->fd); + return; + } + + if (port_associate(priv->port_fd, PORT_SOURCE_FD, (uintptr_t) pollable->fd, pollable->slot, pollable) < 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_ports_eventloop_setselect(): port_associate failed: %d (%s)", errno, strerror(errno)); + } + + return; +} + +static void mowgli_ports_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_ports_eventloop_private_t *priv; + int i, num, o_errno, nget = 1; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + num = port_getn(priv->port_fd, priv->pfd, priv->pfd_size, &nget, + delay >= 0 ? &(struct timespec){ .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); + + o_errno = errno; + mowgli_eventloop_synchronize(eventloop); + + if (num < 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_ports_eventloop_select(): port_getn failed: %d (%s)", o_errno, strerror(o_errno)); + return; + } + + for (i = 0; i < nget; i++) + { + mowgli_eventloop_pollable_t *pollable = priv->pfd[i].portev_user; + + if (priv->pfd[i].portev_events & (POLLIN | POLLHUP | POLLERR) && pollable->read_function != NULL) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (priv->pfd[i].portev_events & (POLLOUT | POLLHUP | POLLERR) && pollable->write_function != NULL) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } +} + +mowgli_eventloop_ops_t _mowgli_ports_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_ports_eventloop_pollsetup, + .pollshutdown = mowgli_ports_eventloop_pollshutdown, + .setselect = mowgli_ports_eventloop_setselect, + .select = mowgli_ports_eventloop_select, + .destroy = mowgli_ports_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/qnx_pollops.c b/src/libmowgli/eventloop/qnx_pollops.c new file mode 100644 index 0000000..7417ef4 --- /dev/null +++ b/src/libmowgli/eventloop/qnx_pollops.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_DISPATCH_BLOCK + +#include <sys/iofunc.h> +#include <sys/dispatch.h> + +typedef struct { + dispatch_t *dpp; + dispatch_context_t *ctp; +} mowgli_qnx_eventloop_private_t; + +static void mowgli_qnx_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_qnx_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_qnx_eventloop_private_t)); + eventloop->poller = priv; + + priv->dpp = dispatch_create(); + + return; +} + +static void mowgli_qnx_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_qnx_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + if (priv->ctp != NULL) + dispatch_context_free(priv->ctp); + + dispatch_destroy(priv->dpp); + mowgli_free(priv); + + return; +} + +static void mowgli_qnx_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_qnx_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + if (select_detach(priv->dpp, pollable->fd) != 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_qnx_eventloop_destroy(): select_detach failed: %d (%s)", errno, strerror(errno)); + } +} + +static void mowgli_qnx_eventloop_event_cb(select_context_t *ctp, mowgli_descriptor_t fd, unsigned int flags, void *userdata) +{ + mowgli_eventloop_t *eventloop; + mowgli_eventloop_pollable_t *pollable; + + return_if_fail(ctp != NULL); + return_if_fail(userdata != NULL); + + pollable = userdata; + eventloop = pollable->eventloop; + + return_if_fail(eventloop != NULL); + + if (flags & (SELECT_FLAG_READ | SELECT_FLAG_EXCEPT)) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (flags & (SELECT_FLAG_WRITE | SELECT_FLAG_EXCEPT)) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); +} + +static void mowgli_qnx_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_qnx_eventloop_private_t *priv; + select_attr_t attr = {}; + unsigned int old_flags; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + old_flags = pollable->slot; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + pollable->slot |= SELECT_FLAG_READ; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + pollable->slot |= SELECT_FLAG_WRITE; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function == NULL) + pollable->slot &= ~SELECT_FLAG_READ; + + if (pollable->write_function == NULL) + pollable->slot &= ~SELECT_FLAG_WRITE; + + if (old_flags == 0 && pollable->slot == 0) + return; + + if (old_flags) + select_detach(priv->dpp, pollable->fd); + + if (pollable->slot) + { + if (select_attach(priv->dpp, &attr, pollable->fd, pollable->slot, mowgli_qnx_eventloop_event_cb, pollable) != 0) + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_qnx_eventloop_setselect(): select_attach failed: %d (%s)", errno, strerror(errno)); + } + } + + return; +} + +static void mowgli_qnx_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + dispatch_context_t *new_ctp; + mowgli_qnx_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + /* set timeout if needed */ + dispatch_timeout(priv->dpp, delay >= 0 ? &(struct timespec){ .tv_sec = delay / 1000, .tv_nsec = delay % 1000 * 1000000 } : NULL); + + if (priv->ctp != NULL) + priv->ctp = dispatch_context_alloc(priv->dpp); + + /* if dispatch_block returns non-NULL, priv->ctp may have been realloc()'d, NULL is error condition */ + if ((new_ctp = dispatch_block(priv->ctp)) != NULL) + priv->ctp = new_ctp; + else + { + if (mowgli_eventloop_ignore_errno(errno)) + return; + + mowgli_log("mowgli_qnx_eventloop_select(): dispatch_block failed: %d (%s)", errno, strerror(errno)); + } + + mowgli_eventloop_synchronize(eventloop); +} + +mowgli_eventloop_ops_t _mowgli_qnx_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_qnx_eventloop_pollsetup, + .pollshutdown = mowgli_qnx_eventloop_pollshutdown, + .setselect = mowgli_qnx_eventloop_setselect, + .select = mowgli_qnx_eventloop_select, + .destroy = mowgli_qnx_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/select_pollops.c b/src/libmowgli/eventloop/select_pollops.c new file mode 100644 index 0000000..467b4f5 --- /dev/null +++ b/src/libmowgli/eventloop/select_pollops.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef HAVE_SELECT + +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif + +typedef struct { + mowgli_list_t pollable_list; +} mowgli_select_eventloop_private_t; + +static void mowgli_select_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + mowgli_select_eventloop_private_t *priv; + + priv = mowgli_alloc(sizeof(mowgli_select_eventloop_private_t)); + eventloop->poller = priv; + + return; +} + +static void mowgli_select_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + mowgli_node_t *n, *tn; + mowgli_select_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + mowgli_node_delete(n, &priv->pollable_list); + } + + mowgli_free(priv); + return; +} + +static void mowgli_select_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_select_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + mowgli_node_delete(&pollable->node, &priv->pollable_list); +} + +static void mowgli_select_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_select_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + if (pollable->read_function || pollable->write_function) + mowgli_node_delete(&pollable->node, &priv->pollable_list); + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function || pollable->write_function) + mowgli_node_add(pollable, &pollable->node, &priv->pollable_list); + + return; +} + +static void mowgli_select_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_node_t *n, *tn; + mowgli_eventloop_pollable_t *pollable; + mowgli_select_eventloop_private_t *priv; + mowgli_descriptor_t highest_fd = 0; + fd_set rfds, wfds, efds; + struct timeval tv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + mowgli_eventloop_pollable_t *pollable = n->data; + +#ifdef DEBUG + mowgli_log("considering fd %d pollable %p count %d", pollable->fd, pollable, priv->pollable_list.count); +#endif + + if (pollable->read_function || pollable->write_function) + { + if (pollable->fd > highest_fd) + highest_fd = pollable->fd; + + if (pollable->read_function) + { + FD_SET(pollable->fd, &rfds); + FD_SET(pollable->fd, &efds); + } + + if (pollable->write_function) + { + FD_SET(pollable->fd, &wfds); + FD_SET(pollable->fd, &efds); + } + } + } + + tv.tv_sec = 1; + + if (select(highest_fd + 1, &rfds, &wfds, &efds, &tv) > 0) + { + mowgli_eventloop_synchronize(eventloop); + + /* iterate twice so we don't touch freed memory if a pollable is destroyed */ + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + pollable = n->data; + + if ((FD_ISSET(pollable->fd, &rfds) || FD_ISSET(pollable->fd, &efds)) && pollable->read_function) + { +#ifdef DEBUG + mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_READ, %p)\n", pollable->read_function, eventloop, pollable, pollable->userdata); +#endif + + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + } + } + + MOWGLI_ITER_FOREACH_SAFE(n, tn, priv->pollable_list.head) + { + pollable = n->data; + + if ((FD_ISSET(pollable->fd, &wfds) || FD_ISSET(pollable->fd, &efds)) && pollable->write_function) + { +#ifdef DEBUG + mowgli_log("run %p(%p, %p, MOWGLI_EVENTLOOP_IO_WRITE, %p)\n", pollable->write_function, eventloop, pollable, pollable->userdata); +#endif + + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } + } + } +} + +mowgli_eventloop_ops_t _mowgli_select_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_select_eventloop_pollsetup, + .pollshutdown = mowgli_select_eventloop_pollshutdown, + .setselect = mowgli_select_eventloop_setselect, + .select = mowgli_select_eventloop_select, + .destroy = mowgli_select_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/eventloop/timer.c b/src/libmowgli/eventloop/timer.c new file mode 100644 index 0000000..d8c5061 --- /dev/null +++ b/src/libmowgli/eventloop/timer.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org> + * Copyright (c) 2005-2007 Atheme Project (http://www.atheme.org) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *timer_heap = NULL; + +static mowgli_eventloop_timer_t *mowgli_timer_add_real(mowgli_eventloop_t *eventloop, + const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when, time_t frequency) +{ + mowgli_eventloop_timer_t *timer; + + return_val_if_fail(eventloop != NULL, NULL); + return_val_if_fail(func != NULL, NULL); + + if (timer_heap == NULL) + timer_heap = mowgli_heap_create(sizeof(mowgli_eventloop_timer_t), 16, BH_NOW); + + timer = mowgli_heap_alloc(timer_heap); + + timer->func = func; + timer->name = name; + timer->arg = arg; + timer->when = mowgli_eventloop_get_time(eventloop) + when; + timer->frequency = frequency; + timer->active = true; + + if (eventloop->deadline <= mowgli_eventloop_get_time(eventloop) || timer->when <= eventloop->deadline) + eventloop->deadline = timer->when; + + mowgli_node_add(timer, &timer->node, &eventloop->timer_list); + +#ifdef DEBUG + mowgli_log("[timer(%p) add when:%d active:%d] [eventloop deadline:%d]", timer, timer->when, timer->active, eventloop->deadline); +#endif + + return timer; +} + +/* add an event to the table to be continually ran */ +mowgli_eventloop_timer_t *mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) +{ + return mowgli_timer_add_real(eventloop, name, func, arg, when, when); +} + +/* adds an event to the table to be ran only once */ +mowgli_eventloop_timer_t *mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when) +{ + return mowgli_timer_add_real(eventloop, name, func, arg, when, 0); +} + +/* delete an event from the table */ +void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer) +{ + return_if_fail(eventloop != NULL); + return_if_fail(timer != NULL); + + if (eventloop->last_ran == timer->name) + eventloop->last_ran = "<removed>"; + + mowgli_node_delete(&timer->node, &eventloop->timer_list); + mowgli_heap_free(timer_heap, timer); +} + +/* checks all pending events */ +void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop) +{ + mowgli_node_t *n, *tn; + time_t currtime; + + return_if_fail(eventloop != NULL); + + currtime = mowgli_eventloop_get_time(eventloop); + + MOWGLI_ITER_FOREACH_SAFE(n, tn, eventloop->timer_list.head) + { + mowgli_eventloop_timer_t *timer = n->data; + + if (timer->active && timer->when <= currtime) + { + /* now we call it */ + eventloop->last_ran = timer->name; + timer->func(timer->arg); + + /* invalidate eventloop sleep-until time */ + eventloop->deadline = -1; + + /* event is scheduled more than once */ + if (timer->frequency) + timer->when = currtime + timer->frequency; + else + { + /* XXX: yuck. find a better way to handle this. */ + eventloop->last_ran = "<onceonly>"; + + mowgli_timer_destroy(eventloop, timer); + } + } + } +} + +/* returns the time the next mowgli_timer_run() should happen */ +time_t mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop) +{ + mowgli_node_t *n; + + return_val_if_fail(eventloop != NULL, 0); + + if (eventloop->deadline == -1) + { + MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head) + { + mowgli_eventloop_timer_t *timer = n->data; + + if (timer->active && (timer->when < eventloop->deadline || eventloop->deadline == -1)) + eventloop->deadline = timer->when; + +#ifdef DEBUG + mowgli_log("timer %p active:%d when:%ld deadline:%ld", timer, timer->active, timer->when, eventloop->deadline); +#endif + } + } + +#ifdef DEBUG + mowgli_log("eventloop deadline:%ld", eventloop->deadline); +#endif + + return eventloop->deadline; +} + +/* finds an event in the table */ +mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg) +{ + mowgli_node_t *n; + + return_val_if_fail(eventloop != NULL, NULL); + return_val_if_fail(func != NULL, NULL); + + MOWGLI_ITER_FOREACH(n, eventloop->timer_list.head) + { + mowgli_eventloop_timer_t *timer = n->data; + + if (timer->func == func && timer->arg == arg) + return timer; + } + + return NULL; +} + +/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs + * vim:ts=8 + * vim:sw=8 + * vim:noexpandtab + */ diff --git a/src/libmowgli/eventloop/windows_pollops.c b/src/libmowgli/eventloop/windows_pollops.c new file mode 100644 index 0000000..f1c9c0f --- /dev/null +++ b/src/libmowgli/eventloop/windows_pollops.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef _WIN32 + +#define DEFAULT_SOCKETMAX (2048) + +typedef struct { + WSAEVENT *pfd; + unsigned short pfd_size; + unsigned short last_slot; + mowgli_eventloop_pollable_t **pollables; +} mowgli_winsock_eventloop_private_t; + +static WSADATA wsock_env; + +void mowgli_winsock_bootstrap(void) +{ + int r; + + r = WSAStartup((short) 0x202, &wsock_env); + if (r != 0) + { + printf("mowgli bootstrap failure (win32): %d\n", r); + exit(EXIT_FAILURE); + } + + if (!wsock_env.iMaxSockets) + wsock_env.iMaxSockets = DEFAULT_SOCKETMAX; + else + wsock_env.iMaxSockets -= (wsock_env.iMaxSockets % MAXIMUM_WAIT_OBJECTS); +} + +static void mowgli_winsock_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + unsigned short i; + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(wsock_env.iMaxSockets > 0); + + priv = mowgli_alloc(sizeof(mowgli_winsock_eventloop_private_t)); + eventloop->poller = priv; + + priv->pfd_size = wsock_env.iMaxSockets; + priv->pfd = mowgli_alloc(sizeof(WSAEVENT) * priv->pfd_size); + priv->pollables = mowgli_alloc(sizeof(mowgli_eventloop_pollable_t *) * priv->pfd_size); + + /* sanitize NT port handle values to a known-good default */ + for (i = 0; i < priv->pfd_size; i++) + { + priv->pfd[i] = INVALID_HANDLE_VALUE; + priv->pollables[i] = NULL; + } + + return; +} + +static unsigned short mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloop_private_t *priv) +{ + unsigned short i = 1; + + return_val_if_fail(priv != NULL, 0); + + if (priv->last_slot) + i = priv->last_slot; + + for (; i < priv->pfd_size; i++) + { + if (priv->pfd[i] == INVALID_HANDLE_VALUE) + { + priv->last_slot = i; + return i; + } + } + + /* miss, try from beginning. */ + for (i = 1; i < priv->pfd_size; i++) + { + if (priv->pfd[i] == INVALID_HANDLE_VALUE) + { + priv->last_slot = i; + return i; + } + } + + /* if this happens, we're boned... */ + mowgli_log("out of handles for eventloop %p, aborting\n", priv); + abort(); + + return 0; +} + +static void mowgli_winsock_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + unsigned short i; + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + for (i = 0; i < priv->pfd_size; i++) + { + WSACloseEvent(priv->pfd[i]); + priv->pfd[i] = INVALID_HANDLE_VALUE; + } + + mowgli_free(priv->pfd); + mowgli_free(priv); + + return; +} + +static void mowgli_winsock_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + if (pollable->slot) + { + WSAEventSelect(pollable->fd, priv->pfd[pollable->slot], 0); + WSACloseEvent(priv->pfd[pollable->slot]); + + priv->pfd[pollable->slot] = INVALID_HANDLE_VALUE; + priv->pollables[pollable->slot] = NULL; + } + + pollable->slot = 0; + pollable->events = 0; +} + +static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_winsock_eventloop_private_t *priv; + unsigned int old_flags; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + old_flags = pollable->events; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + pollable->events |= (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB); + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + pollable->events |= (FD_WRITE | FD_CONNECT | FD_CLOSE); + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function == NULL) + pollable->events &= ~(FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB); + + if (pollable->write_function == NULL) + pollable->events &= ~(FD_WRITE | FD_CONNECT | FD_CLOSE); + + if (old_flags == 0 && pollable->events == 0) + return; + else if (pollable->events <= 0) + { + mowgli_winsock_eventloop_destroy(eventloop, pollable); + return; + } + + /* set up the HANDLE if we have not already */ + if (!pollable->slot) + { + pollable->slot = mowgli_winsock_eventloop_find_slot(priv); + + priv->pfd[pollable->slot] = WSACreateEvent(); + priv->pollables[pollable->slot] = pollable; + } + + if (WSAEventSelect(pollable->fd, priv->pfd[pollable->slot], pollable->events) != 0) + { + if (mowgli_eventloop_ignore_errno(WSAGetLastError())) + return; + + mowgli_log("mowgli_winsock_eventloop_setselect(): WSAEventSelect failed: %d", WSAGetLastError()); + } + + return; +} + +static void mowgli_winsock_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_winsock_eventloop_private_t *priv; + int i, j; + DWORD result; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + return_if_fail(priv->pfd_size % MAXIMUM_WAIT_OBJECTS == 0); + + for (i = 0; i < priv->pfd_size; i += MAXIMUM_WAIT_OBJECTS) + { + result = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, priv->pfd + i, FALSE, delay); + + if (result == WAIT_FAILED) + { + if (mowgli_eventloop_ignore_errno(WSAGetLastError())) + return; + + mowgli_log("mowgli_winsock_eventloop_select(): WaitForMultipleObjects failed: %d", WSAGetLastError()); + return; + } + + for (j = (result - WAIT_OBJECT_0); j < MAXIMUM_WAIT_OBJECTS; j++) + { + mowgli_eventloop_pollable_t *pollable = priv->pollables[i + j]; + WSANETWORKEVENTS events; + + WSAEnumNetworkEvents(pollable->fd, priv->pfd[pollable->slot], &events); + + if (events.lNetworkEvents & (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB) && pollable->read_function != NULL) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE) && pollable->write_function != NULL) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } + } + + mowgli_eventloop_synchronize(eventloop); +} + +mowgli_eventloop_ops_t _mowgli_winsock_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_winsock_eventloop_pollsetup, + .pollshutdown = mowgli_winsock_eventloop_pollshutdown, + .setselect = mowgli_winsock_eventloop_setselect, + .select = mowgli_winsock_eventloop_select, + .destroy = mowgli_winsock_eventloop_destroy, +}; + +#endif diff --git a/src/libmowgli/ext/Makefile b/src/libmowgli/ext/Makefile new file mode 100644 index 0000000..d7466b6 --- /dev/null +++ b/src/libmowgli/ext/Makefile @@ -0,0 +1,25 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_EXT} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_EXT} + +SRCS = confparse.c \ + error_backtrace.c \ + getopt_long.c \ + global_storage.c \ + program_opts.c \ + proctitle.c + +INCLUDES = confparse.h \ + error_backtrace.h \ + getopt_long.h \ + global_storage.h \ + program_opts.h \ + proctitle.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/ext + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/ext/confparse.c b/src/libmowgli/ext/confparse.c new file mode 100644 index 0000000..898ba8c --- /dev/null +++ b/src/libmowgli/ext/confparse.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2005-2011 Atheme Project (http://www.atheme.org) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Description of config files parsed by this: + * + * configfile = *WS *configentry + * configentry = value [1*WS value] [1*WS "{" *(configentry 1*WS) "}" ] *WS ";" + * value = 1*achar / DQUOTE *qchar DQUOTE + * achar = <any CHAR except WS or DQUOTE> + * qchar = <any CHAR except DQUOTE or \> / "\\" / "\" DQUOTE + * comment = "/" "*" <anything except * /> "*" "/" / + * "#" *CHAR %0x0A / + * "//" *CHAR %0x0A + * WS = %x09 / %x0A / %x0D / SPACE / "=" / comment + * + * A value of "include" for toplevel configentries causes a file to be + * included. The included file is logically appended to the current file, + * no matter where the include directive is. Include files must have balanced + * braces. + */ +/* + * Original idea from the csircd config parser written by Fred Jacobs + * and Chris Behrens. + */ + +#include "mowgli.h" +#include <sys/stat.h> +#include <limits.h> + +#define MAX_INCLUDE_NESTING 16 + +static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata); +static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr); +static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename); + +#define CF_ERRORED(cf) ((cf)->curline <= 0) + +static void mowgli_config_file_error(mowgli_config_file_t *cf, const char *format, ...) +{ + va_list ap; + char buffer[1024]; + char *ptr; + + va_start(ap, format); + vsnprintf(buffer, sizeof buffer, format, ap); + va_end(ap); + + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + + if (cf != NULL) + { + if (cf->curline < 0) + cf->curline = -cf->curline; + + mowgli_log("%s:%d: %s", cf->filename, cf->curline, buffer); + + /* mark config parse as failed */ + cf->curline = -cf->curline; + } + else + mowgli_log("mowgli_config_file_parse(): %s", buffer); +} + +static void skip_ws(char **pos, mowgli_config_file_t *cf) +{ + int startline; + + for (;;) + { + switch (**pos) + { + case ' ': + case '\t': + case '\r': + case '=': /* XXX */ + break; + case '\n': + cf->curline++; + break; + case '/': + if ((*pos)[1] == '*') + { + startline = cf->curline; + (*pos)++; + (*pos)++; + while (**pos != '\0' && (**pos != '*' || (*pos)[1] != '/')) + { + if (**pos == '\n') + cf->curline++; + (*pos)++; + } + if (**pos == '\0') + mowgli_config_file_error(cf, "File ends inside comment starting at line %d", startline); + else + (*pos)++; /* skip '*' */ + } + else if ((*pos)[1] == '/') + { + while (**pos != '\0' && **pos != '\n' && **pos != '\r') + (*pos)++; + continue; + } + else + return; + break; + case '#': + while (**pos != '\0' && **pos != '\n' && **pos != '\r') + (*pos)++; + continue; + default: + return; + } + if (**pos == '\0') + return; + (*pos)++; + } +} + +static char *get_value(char **pos, mowgli_config_file_t *cf, char *skipped) +{ + char *p = *pos; + char *q; + char *start; + + *skipped = '\0'; + if (*p == '"') + { + p++; + start = p; + q = p; + while (*p != '\0' && *p != '\r' && *p != '\n' && *p != '"') + { + if (*p == '\\' && (p[1] == '"' || p[1] == '\\')) + p++; + *q++ = *p++; + } + if (*p == '\0') + { + mowgli_config_file_error(cf, "File ends inside quoted string"); + return NULL; + } + if (*p == '\r' || *p == '\n') + { + mowgli_config_file_error(cf, "Newline inside quoted string"); + return NULL; + } + if (*p != '"') + { + mowgli_config_file_error(cf, "Weird character terminating quoted string (BUG)"); + return NULL; + } + p++; + *q = '\0'; + *pos = p; + skip_ws(pos, cf); + return start; + } + else + { + start = p; + while (*p != '\0' && *p != '\t' && *p != '\r' && *p != '\n' && + *p != ' ' && *p != '/' && *p != '#' && + *p != ';' && *p != '{' && *p != '}') + p++; + if (p == start) + return NULL; + *pos = p; + skip_ws(pos, cf); + if (p == *pos) + *skipped = *p; + *p = '\0'; + if (p == *pos) + (*pos)++; + return start; + } +} + +static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata) +{ + mowgli_config_file_t *cf, *subcf, *lastcf; + mowgli_config_file_entry_t **pprevce, *ce, *upce; + char *p, *val; + char c; + + cf = mowgli_alloc(sizeof *cf); + cf->filename = mowgli_strdup(filename); + cf->curline = 1; + cf->mem = confdata; + lastcf = cf; + pprevce = &cf->entries; + upce = NULL; + p = confdata; + while (*p != '\0') + { + skip_ws(&p, cf); + if (*p == '\0' || CF_ERRORED(cf)) + break; + if (*p == '}') + { + if (upce == NULL) + { + mowgli_config_file_error(cf, "Extraneous closing brace"); + break; + } + ce = upce; + ce->sectlinenum = cf->curline; + pprevce = &ce->next; + upce = ce->prevlevel; + p++; + skip_ws(&p, cf); + if (CF_ERRORED(cf)) + break; + if (*p != ';') + { + mowgli_config_file_error(cf, "Missing semicolon after closing brace for section ending at line %d", ce->sectlinenum); + break; + } + ce = NULL; + p++; + continue; + } + val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) + break; + if (val == NULL) + { + mowgli_config_file_error(cf, "Unexpected character trying to read variable name"); + break; + } + ce = mowgli_alloc(sizeof *ce); + ce->fileptr = cf; + ce->varlinenum = cf->curline; + ce->varname = val; + ce->prevlevel = upce; + *pprevce = ce; + pprevce = &ce->next; + if (c == '\0' && (*p == '{' || *p == ';')) + c = *p++; + if (c == '{') + { + pprevce = &ce->entries; + upce = ce; + ce = NULL; + } + else if (c == ';') + { + ce = NULL; + } + else if (c != '\0') + { + mowgli_config_file_error(cf, "Unexpected characters after unquoted string %s", ce->varname); + break; + } + else + { + val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) + break; + if (val == NULL) + { + mowgli_config_file_error(cf, "Unexpected character trying to read value for %s", ce->varname); + break; + } + ce->vardata = val; + if (c == '\0' && (*p == '{' || *p == ';')) + c = *p++; + if (c == '{') + { + pprevce = &ce->entries; + upce = ce; + ce = NULL; + } + else if (c == ';') + { + if (upce == NULL && !strcasecmp(ce->varname, "include")) + { + subcf = mowgli_config_file_load_internal(cf, ce->vardata); + if (subcf == NULL) + { + mowgli_config_file_error(cf, "Error in file included from here"); + break; + } + lastcf->next = subcf; + while (lastcf->next != NULL) + lastcf = lastcf->next; + } + ce = NULL; + } + else + { + mowgli_config_file_error(cf, "Unexpected characters after value %s %s", ce->varname, ce->vardata); + break; + } + } + } + if (!CF_ERRORED(cf) && upce != NULL) + { + mowgli_config_file_error(cf, "One or more sections not closed"); + ce = upce; + while (ce->prevlevel != NULL) + ce = ce->prevlevel; + if (ce->vardata != NULL) + mowgli_config_file_error(cf, "First unclosed section is %s %s at line %d", + ce->varname, ce->vardata, ce->varlinenum); + else + mowgli_config_file_error(cf, "First unclosed section is %s at line %d", + ce->varname, ce->varlinenum); + } + if (CF_ERRORED(cf)) + { + mowgli_config_file_free(cf); + cf = NULL; + } + return cf; +} + +static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr) +{ + mowgli_config_file_entry_t *nptr; + + for (; ceptr; ceptr = nptr) + { + nptr = ceptr->next; + if (ceptr->entries) + mowgli_config_file_entry_free(ceptr->entries); + /* ce_varname and ce_vardata are inside cf_mem */ + mowgli_free(ceptr); + } +} + +void mowgli_config_file_free(mowgli_config_file_t *cfptr) +{ + mowgli_config_file_t *nptr; + + for (; cfptr; cfptr = nptr) + { + nptr = cfptr->next; + if (cfptr->entries) + mowgli_config_file_entry_free(cfptr->entries); + mowgli_free(cfptr->filename); + mowgli_free(cfptr->mem); + mowgli_free(cfptr); + } +} + +static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename) +{ + struct stat sb; + FILE *fp; + size_t ret; + char *buf = NULL; + mowgli_config_file_t *cfptr; + static int nestcnt; + + if (nestcnt > MAX_INCLUDE_NESTING) + { + mowgli_config_file_error(parent, "Includes nested too deep \"%s\"\n", filename); + return NULL; + } + + fp = fopen(filename, "rb"); + if (!fp) + { + mowgli_config_file_error(parent, "Couldn't open \"%s\": %s\n", filename, strerror(errno)); + return NULL; + } + if (stat(filename, &sb) == -1) + { + mowgli_config_file_error(parent, "Couldn't fstat \"%s\": %s\n", filename, strerror(errno)); + fclose(fp); + return NULL; + } + if (!S_ISREG(sb.st_mode)) + { + mowgli_config_file_error(parent, "Not a regular file: \"%s\"\n", filename); + fclose(fp); + return NULL; + } + if (sb.st_size > SSIZE_MAX - 1) + { + mowgli_config_file_error(parent, "File too large: \"%s\"\n", filename); + fclose(fp); + return NULL; + } + buf = (char *) mowgli_alloc(sb.st_size + 1); + if (sb.st_size) + { + errno = 0; + ret = fread(buf, 1, sb.st_size, fp); + if (ret != (size_t)sb.st_size) + { + mowgli_config_file_error(parent, "Error reading \"%s\": %s\n", filename, strerror(errno ? errno : EFAULT)); + mowgli_free(buf); + fclose(fp); + return NULL; + } + } + else + ret = 0; + buf[ret] = '\0'; + fclose(fp); + nestcnt++; + cfptr = mowgli_config_file_parse(filename, buf); + nestcnt--; + /* buf is owned by cfptr or freed now */ + return cfptr; +} + +mowgli_config_file_t *mowgli_config_file_load(const char *filename) +{ + return mowgli_config_file_load_internal(NULL, filename); +} + +/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs + * vim:ts=8 + * vim:sw=8 + * vim:noexpandtab + */ diff --git a/src/libmowgli/ext/confparse.h b/src/libmowgli/ext/confparse.h new file mode 100644 index 0000000..d498b87 --- /dev/null +++ b/src/libmowgli/ext/confparse.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2008 William Pitcock, et al. + * Rights to this code are as documented in doc/LICENSE. + * + * Config file parser. + * + */ + +#ifndef CONFPARSE_H +#define CONFPARSE_H + +typedef struct _mowgli_configfile mowgli_config_file_t; +typedef struct _mowgli_configentry mowgli_config_file_entry_t; + +struct _mowgli_configfile +{ + char *filename; + mowgli_config_file_entry_t *entries; + mowgli_config_file_t *next; + int curline; + char *mem; +}; + +struct _mowgli_configentry +{ + mowgli_config_file_t *fileptr; + + int varlinenum; + char *varname; + char *vardata; + int sectlinenum; /* line containing closing brace */ + + mowgli_config_file_entry_t *entries; + mowgli_config_file_entry_t *prevlevel; + mowgli_config_file_entry_t *next; +}; + +/* confp.c */ +extern void mowgli_config_file_free(mowgli_config_file_t *cfptr); +extern mowgli_config_file_t *mowgli_config_file_load(const char *filename); + +#endif + +/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs ts=8 sw=8 noexpandtab + */ diff --git a/src/libmowgli/mowgli_error_backtrace.c b/src/libmowgli/ext/error_backtrace.c index 02b7b4e..6c28c22 100644 --- a/src/libmowgli/mowgli_error_backtrace.c +++ b/src/libmowgli/ext/error_backtrace.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_error_backtrace.c: Print errors and explain how they were reached. + * error_backtrace.c: Print errors and explain how they were reached. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -39,7 +39,7 @@ mowgli_error_context_display(mowgli_error_context_t *e, const char *delim) { bt_msg = (char *) n->data; - printf("%s%s", bt_msg, n->next != NULL ? delim : "\n"); + fprintf(stderr, "%s%s", bt_msg, n->next != NULL ? delim : "\n"); } } @@ -71,9 +71,9 @@ void mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error) { mowgli_error_context_display(e, delim); - printf("Error: %s\n", error); + fprintf(stderr, "Error: %s\n", error); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } void @@ -89,7 +89,7 @@ mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...) vsnprintf(buf, 65535, msg, va); va_end(va); - mowgli_node_add(strdup(buf), mowgli_node_create(), &e->bt); + mowgli_node_add(mowgli_strdup(buf), mowgli_node_create(), &e->bt); } void diff --git a/src/libmowgli/mowgli_error_backtrace.h b/src/libmowgli/ext/error_backtrace.h index 57970b0..d7da7cf 100644 --- a/src/libmowgli/mowgli_error_backtrace.h +++ b/src/libmowgli/ext/error_backtrace.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_error_backtrace.h: Print errors and explain how they were reached. + * error_backtrace.h: Print errors and explain how they were reached. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/ext/getopt_long.c b/src/libmowgli/ext/getopt_long.c new file mode 100644 index 0000000..adf64e5 --- /dev/null +++ b/src/libmowgli/ext/getopt_long.c @@ -0,0 +1,461 @@ +/* $NetBSD: getopt_long.c,v 1.25 2009/03/20 14:05:54 joerg Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <mowgli.h> + +#include "getopt_long.h" + +int mowgli_opterr = 1; /* if error message should be printed */ +int mowgli_optind = 1; /* index into parent argv vector */ +int mowgli_optopt = '?'; /* character checked for validity */ +int mowgli_optreset = 0; /* reset getopt */ +char *mowgli_optarg = NULL; /* argument associated with option */ + +/* XXX: suppress const warnings */ +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) + +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((mowgli_opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) +#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +/* XXX: GNU ignores PC if *options == '-' */ +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static inline void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static int getopt_internal(int, char **, const char *); +static int gcd(int, int); +static void permute_args(int, int, int, char **); + +static const char *place = EMSG; /* option letter processing */ + +/* XXX: set mowgli_optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return b; +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + return_if_fail(nargv != NULL); + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + nargv[pos] = nargv[cstart]; + nargv[cstart] = swap; + } + } +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + * Returns -2 if -- is found (can be long option or end of options marker). + */ +static int +getopt_internal(int nargc, char **nargv, const char *options) +{ + char *oli; /* option letter list index */ + int optchar; + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + + mowgli_optarg = NULL; + + /* + * XXX Some programs (like rsyncd) expect to be able to + * XXX re-initialize mowgli_optind to 0 and have getopt_long(3) + * XXX properly function again. Work around this braindamage. + */ + if (mowgli_optind == 0) + mowgli_optind = 1; + + if (mowgli_optreset) + nonopt_start = nonopt_end = -1; +start: + if (mowgli_optreset || !*place) { /* update scanning pointer */ + mowgli_optreset = 0; + if (mowgli_optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + mowgli_optind, nargv); + mowgli_optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set mowgli_optind + * to the first of them. + */ + mowgli_optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((*(place = nargv[mowgli_optind]) != '-') + || (place[1] == '\0')) { /* found non-option */ + place = EMSG; + if (IN_ORDER) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + mowgli_optarg = nargv[mowgli_optind++]; + return INORDER; + } + if (!PERMUTE) { + /* + * if no permutation wanted, stop parsing + * at first non-option + */ + return -1; + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = mowgli_optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + mowgli_optind, nargv); + nonopt_start = mowgli_optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + mowgli_optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = mowgli_optind; + if (place[1] && *++place == '-') { /* found "--" */ + place++; + return -2; + } + } + if ((optchar = (int)*place++) == (int)':' || + (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { + /* option letter unknown or ':' */ + if (!*place) + ++mowgli_optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + mowgli_optopt = optchar; + return BADCH; + } + if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ + /* XXX: what if no long options provided (called by getopt)? */ + if (*place) + return -2; + + if (++mowgli_optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + mowgli_optopt = optchar; + return BADARG; + } else /* white space */ + place = nargv[mowgli_optind]; + /* + * Handle -W arg the same as --arg (which causes getopt to + * stop parsing). + */ + return -2; + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++mowgli_optind; + } else { /* takes (optional) argument */ + mowgli_optarg = NULL; + if (*place) /* no white space */ + mowgli_optarg = __UNCONST(place); + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++mowgli_optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + mowgli_optopt = optchar; + return BADARG; + } else + mowgli_optarg = nargv[mowgli_optind]; + } + place = EMSG; + ++mowgli_optind; + } + /* dump back option letter */ + return optchar; +} + +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the real getopt] + */ +int +mowgli_getopt(nargc, nargv, options) + int nargc; + char * const *nargv; + const char *options; +{ + int retval; + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + + retval = getopt_internal(nargc, __UNCONST(nargv), options); + if (retval == -2) { + ++mowgli_optind; + /* + * We found an option (--), so if we skipped non-options, + * we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, mowgli_optind, + __UNCONST(nargv)); + mowgli_optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + retval = -1; + } + return retval; +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +mowgli_getopt_long(int nargc, char * const *nargv, const char *options, + const mowgli_getopt_option_t *long_options, int *idx) +{ + int retval; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + return_val_if_fail(long_options != NULL, -1); + /* idx may be NULL */ + + retval = getopt_internal(nargc, __UNCONST(nargv), options); + if (retval == -2) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + + current_argv = __UNCONST(place); + match = -1; + ambiguous = 0; + + mowgli_optind++; + place = EMSG; + + if (*current_argv == '\0') { /* found "--" */ + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + mowgli_optind, __UNCONST(nargv)); + mowgli_optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == + (unsigned)current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + mowgli_optopt = 0; + return BADCH; + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets mowgli_optopt to val regardless of + * flag + */ + if (long_options[match].flag == NULL) + mowgli_optopt = long_options[match].val; + else + mowgli_optopt = 0; + return BADARG; + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + mowgli_optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use + * next nargv + */ + mowgli_optarg = nargv[mowgli_optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (mowgli_optarg == NULL)) { + /* + * Missing argument; leading ':' + * indicates no error should be generated + */ + if (PRINT_ERROR) + warnx(recargstring, current_argv); + /* + * XXX: GNU sets mowgli_optopt to val regardless + * of flag + */ + if (long_options[match].flag == NULL) + mowgli_optopt = long_options[match].val; + else + mowgli_optopt = 0; + --mowgli_optind; + return BADARG; + } + } else { /* unknown option */ + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + mowgli_optopt = 0; + return BADCH; + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (idx) + *idx = match; + } + return retval; +#undef IDENTICAL_INTERPRETATION +} diff --git a/src/libmowgli/ext/getopt_long.h b/src/libmowgli/ext/getopt_long.h new file mode 100644 index 0000000..94c90a9 --- /dev/null +++ b/src/libmowgli/ext/getopt_long.h @@ -0,0 +1,69 @@ +/* $NetBSD: getopt.h,v 1.11 2008/04/28 20:22:54 martin Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +/* + * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +typedef struct { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; + /* internal value */ + int iflag; +} mowgli_getopt_option_t; + +extern int mowgli_getopt(int nargc, char * const *nargv, const char *options); + +extern int mowgli_getopt_long(int, char * const *, const char *, + const mowgli_getopt_option_t *, int *); + +extern int mowgli_opterr; +extern int mowgli_optind; +extern int mowgli_optopt; +extern int mowgli_optreset; +extern char *mowgli_optarg; + +#endif /* !_GETOPT_H_ */ diff --git a/src/libmowgli/mowgli_global_storage.c b/src/libmowgli/ext/global_storage.c index c74c6cb..4fec74d 100644 --- a/src/libmowgli/mowgli_global_storage.c +++ b/src/libmowgli/ext/global_storage.c @@ -1,8 +1,8 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_global_storage.c: Simple key->value global storage tool. + * global_storage.c: Simple key->value global storage tool. * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2007, 2011 William Pitcock <nenolod@dereferenced.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,7 +24,7 @@ #include "mowgli.h" static mowgli_patricia_t *mowgli_global_storage_dict = NULL; -static mowgli_spinlock_t *mowgli_global_storage_lock = NULL; +static mowgli_mutex_t mowgli_global_storage_lock; static void _storage_key_canon(char *key) { @@ -32,10 +32,11 @@ static void _storage_key_canon(char *key) } void -mowgli_global_storage_init(void) +mowgli_global_storage_bootstrap(void) { mowgli_global_storage_dict = mowgli_patricia_create(_storage_key_canon); - mowgli_global_storage_lock = mowgli_spinlock_create(); + + mowgli_mutex_init(&mowgli_global_storage_lock); } void * @@ -43,10 +44,9 @@ mowgli_global_storage_get(char *name) { void *ret; - /* name serves as lock token */ - mowgli_spinlock_lock(mowgli_global_storage_lock, name, NULL); + mowgli_mutex_lock(&mowgli_global_storage_lock); ret = mowgli_patricia_retrieve(mowgli_global_storage_dict, name); - mowgli_spinlock_unlock(mowgli_global_storage_lock, name, NULL); + mowgli_mutex_unlock(&mowgli_global_storage_lock); return ret; } @@ -54,15 +54,16 @@ mowgli_global_storage_get(char *name) void mowgli_global_storage_put(char *name, void *value) { - mowgli_spinlock_lock(mowgli_global_storage_lock, NULL, name); + mowgli_mutex_lock(&mowgli_global_storage_lock); mowgli_patricia_add(mowgli_global_storage_dict, name, value); - mowgli_spinlock_unlock(mowgli_global_storage_lock, NULL, name); + mowgli_mutex_unlock(&mowgli_global_storage_lock); } void mowgli_global_storage_free(char *name) { - mowgli_spinlock_lock(mowgli_global_storage_lock, name, name); + mowgli_mutex_lock(&mowgli_global_storage_lock); mowgli_patricia_delete(mowgli_global_storage_dict, name); - mowgli_spinlock_unlock(mowgli_global_storage_lock, name, name); + mowgli_mutex_unlock(&mowgli_global_storage_lock); } + diff --git a/src/libmowgli/mowgli_global_storage.h b/src/libmowgli/ext/global_storage.h index aa60c03..a26e699 100644 --- a/src/libmowgli/mowgli_global_storage.h +++ b/src/libmowgli/ext/global_storage.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_global_storage.h: Simple key->value global storage tool. + * global_storage.h: Simple key->value global storage tool. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -24,7 +24,7 @@ #ifndef MOWGLI_GLOBAL_STORAGE_H #define MOWGLI_GLOBAL_STORAGE_H -extern void mowgli_global_storage_init(void); +extern void mowgli_global_storage_bootstrap(void); extern void *mowgli_global_storage_get(char *name); extern void mowgli_global_storage_put(char *name, void *value); extern void mowgli_global_storage_free(char *name); diff --git a/src/libmowgli/ext/proctitle.c b/src/libmowgli/ext/proctitle.c new file mode 100644 index 0000000..91885d5 --- /dev/null +++ b/src/libmowgli/ext/proctitle.c @@ -0,0 +1,311 @@ +/* + * Code has been calqued from PostgreSQL 9.1 by Elizabeth J. Myers. + * Below is their copyright header. + * + * Do note I've made extensive changes to this code, including adding + * Linux (and Irix?) prctl support. + */ + +/*-------------------------------------------------------------------- + * ps_status.c + * + * Routines to support changing the ps display of PostgreSQL backends + * to contain some useful information. Mechanism differs wildly across + * platforms. + * + * src/backend/utils/misc/ps_status.c + * + * Copyright (c) 2000-2011, PostgreSQL Global Development Group + * various details abducted from various places + *-------------------------------------------------------------------- + */ + +#include "mowgli.h" + +#ifdef HAVE_SYS_PSTAT_H +#include <sys/pstat.h> /* for HP-UX */ +#endif +#ifdef HAVE_PS_STRINGS +#include <machine/vmparam.h> /* for old BSD */ +#include <sys/exec.h> +#endif +#if defined(__darwin__) +#include <crt_externs.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif + +extern char **environ; + +/* + * Alternative ways of updating ps display: + * + * MOWGLI_SETPROC_USE_SETPROCTITLE + * use the function setproctitle(const char *, ...) + * (newer BSD systems) + * MOWGLI_SETPROC_USE_PSTAT + * use the pstat(PSTAT_SETCMD, ) + * (HPUX) + * MOWGLI_SETPROC_USE_PS_STRINGS + * assign PS_STRINGS->ps_argvstr = "string" + * (some BSD systems) + * MOWGLI_SETPROC_USE_PRCTL + * use prctl(PR_SET_NAME, ...) + * (Newer Linux and possibly Irix? -- Note some utilities don't use this name) + * MOWGLI_SETPROC_USE_CHANGE_ARGV + * assign argv[0] = "string" + * (some other BSD systems) + * MOWGLI_SETPROC_USE_CLOBBER_ARGV + * write over the argv and environment area + * (Old Linux and most SysV-like systems) + * MOWGLI_SETPROC_USE_WIN32 + * push the string out as the name of a Windows event + * MOWGLI_SETPROC_USE_NONE + * don't update ps display + * (This is the default, as it is safest.) + */ +#if defined(HAVE_SETPROCTITLE) +#define MOWGLI_SETPROC_USE_SETPROCTITLE +#elif defined(PR_SET_NAME) && defined(HAVE_SYS_PRCTL_H) +#define MOWGLI_SETPROC_USE_PRCTL +#elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD) +#define MOWGLI_SETPROC_USE_PSTAT +#elif defined(HAVE_PS_STRINGS) +#define MOWGLI_SETPROC_USE_PS_STRINGS +#elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__) +#define MOWGLI_SETPROC_USE_CHANGE_ARGV +#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__) +#define MOWGLI_SETPROC_USE_CLOBBER_ARGV +#elif defined(WIN32) +#define MOWGLI_SETPROC_USE_WIN32 +#else +#define MOWGLI_SETPROC_USE_NONE +#endif + + +/* Different systems want the buffer padded differently */ +#if defined(_AIX) || defined(__linux__) || defined(__svr4__) || defined(__darwin__) +#define PS_PADDING '\0' +#else +#define PS_PADDING ' ' +#endif + + +#ifndef MOWGLI_SETPROC_USE_CLOBBER_ARGV +/* all but one option need a buffer to write their ps line in */ +#define PS_BUFFER_SIZE 256 +static char ps_buffer[PS_BUFFER_SIZE]; +static const size_t ps_buffer_size = PS_BUFFER_SIZE; +#else /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +static char *ps_buffer; /* will point to argv area */ +static size_t ps_buffer_size; /* space determined at run time */ +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + +static size_t ps_buffer_fixed_size; +static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */ + +/* save the original argv[] location here */ +static int save_argc; +static char **save_argv; + +/* + * Call this early in startup to save the original argc/argv values. + * If needed, we make a copy of the original argv[] array to preserve it + * from being clobbered by subsequent ps_display actions. + * + * (The original argv[] will not be overwritten by this routine, but may be + * overwritten during mowgli_proctitle_set. Also, the physical location of the + * environment strings may be moved, so this should be called before any code + * that might try to hang onto a getenv() result.) + */ +char ** +mowgli_proctitle_init(int argc, char **argv) +{ + save_argc = argc; + save_argv = argv; + +#if defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + + /* + * If we're going to overwrite the argv area, count the available space. + * Also move the environment to make additional room. + */ + char *end_of_area = NULL; + char **new_environ; + int i; + + /* + * check for contiguous argv strings + */ + for (i = 0; i < argc; i++) + { + if (i == 0 || end_of_area + 1 == argv[i]) + end_of_area = argv[i] + strlen(argv[i]); + } + + if (end_of_area == NULL) /* probably can't happen? */ + { + ps_buffer = NULL; + ps_buffer_size = 0; + return argv; + } + + /* + * check for contiguous environ strings following argv + */ + for (i = 0; environ[i] != NULL; i++) + { + if (end_of_area + 1 == environ[i]) + end_of_area = environ[i] + strlen(environ[i]); + } + + ps_buffer = argv[0]; + ps_buffer_size = end_of_area - argv[0]; + + /* + * move the environment out of the way + */ + new_environ = (char **) mowgli_alloc((i + 1) * sizeof(char *)); + for (i = 0; environ[i] != NULL; i++) + new_environ[i] = mowgli_strdup(environ[i]); + new_environ[i] = NULL; + environ = new_environ; + +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + +#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + + /* + * If we're going to change the original argv[] then make a copy for + * argument parsing purposes. + * + * (NB: do NOT think to remove the copying of argv[]. + * On some platforms, getopt() keeps pointers into the argv array, and will + * get horribly confused when it is re-called to analyze a subprocess' + * argument string if the argv storage has been clobbered meanwhile. Other + * platforms have other dependencies on argv[]. + */ + + char **new_argv; + int i; + + new_argv = (char **) mowgli_alloc((argc + 1) * sizeof(char *)); + for (i = 0; i < argc; i++) + new_argv[i] = mowgli_strdup(argv[i]); + new_argv[argc] = NULL; + +#if defined(__darwin__) + /* + * Darwin (and perhaps other NeXT-derived platforms?) has a static + * copy of the argv pointer, which we may fix like so: + */ + *_NSGetArgv() = new_argv; +#endif + + argv = new_argv; + +#endif /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + + return argv; +} + +void +mowgli_proctitle_set(const char *fmt, ...) +{ +#ifndef MOWGLI_SETPROC_USE_NONE + va_list va; + +#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + if (!save_argv) + return; +#endif + + va_start(va, fmt); + vsnprintf(ps_buffer, ps_buffer_size, fmt, va); + va_end(va); + + return_if_fail(*ps_buffer == '\0'); + + ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer); + +#ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV + save_argv[0] = ps_buffer; + save_argv[1] = NULL; +#endif + +#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV + for (int i = 1; i < save_argc; i++) + save_argv[i] = ps_buffer + ps_buffer_size; + + /* Pad unused bytes */ + printf("%d %d\n", ps_buffer_size, ps_buffer_cur_len); + memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, ps_buffer_size - ps_buffer_cur_len + 1); +#endif + +#ifdef MOWGLI_SETPROC_USE_SETPROCTITLE + setproctitle("%s", ps_buffer); +#endif + +#ifdef MOWGLI_SETPROC_USE_PRCTL + /* Limit us to 16 chars to be safe */ + char procbuf[16]; + mowgli_strlcpy(procbuf, ps_buffer, sizeof(procbuf)); + prctl(PR_SET_NAME, procbuf, 0, 0, 0); + printf("%s\n", procbuf); +#endif + +#ifdef MOWGLI_SETPROC_USE_PSTAT + union pstun pst; + + pst.pst_command = ps_buffer; + pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0); +#endif /* MOWGLI_SETPROC_USE_PSTAT */ + +#ifdef MOWGLI_SETPROC_USE_PS_STRINGS + PS_STRINGS->ps_nargvstr = 1; + PS_STRINGS->ps_argvstr = ps_buffer; +#endif /* MOWGLI_SETPROC_USE_PS_STRINGS */ + +#ifdef MOWGLI_SETPROC_USE_WIN32 + /* + * Win32 does not support showing any changed arguments. To make it at + * all possible to track which backend is doing what, we create a + * named object that can be viewed with for example Process Explorer. + */ + static HANDLE ident_handle = INVALID_HANDLE_VALUE; + char name[PS_BUFFER_SIZE + 32]; + + if (ident_handle != INVALID_HANDLE_VALUE) + CloseHandle(ident_handle); + + sprintf(name, "mowgli_ident(%d): %s", getpid(), ps_buffer); + + ident_handle = CreateEvent(NULL, TRUE, FALSE, name); +#endif /* MOWGLI_SETPROC_USE_WIN32 */ +#endif /* not MOWGLI_SETPROC_USE_NONE */ +} + + +/* + * Returns what's currently in the ps display, in case someone needs + * it. Note that only the activity part is returned. On some platforms + * the string will not be null-terminated, so return the effective + * length into *displen. + */ +const char * +mowgli_proctitle_get(int *displen) +{ +#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV + /* If ps_buffer is a pointer, it might still be null */ + if (!ps_buffer) + { + *displen = 0; + return ""; + } +#endif + + *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size); + + return ps_buffer + ps_buffer_fixed_size; +} diff --git a/src/libmowgli/ext/proctitle.h b/src/libmowgli/ext/proctitle.h new file mode 100644 index 0000000..479ee84 --- /dev/null +++ b/src/libmowgli/ext/proctitle.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * ps_status.h + * + * Declarations for backend/utils/misc/ps_status.c + * + * src/include/utils/ps_status.h + * + *------------------------------------------------------------------------- + */ + +#ifndef __PS_STATUS_H__ +#define __PS_STATUS_H__ + +extern bool mowgli_proctitle_update; + +extern char **mowgli_proctitle_init(int argc, char **argv); + +extern void mowgli_proctitle_set(const char *fmt, ...); + +extern const char *mowgli_proctitle_get(int *displen); + +#endif /* __PS_STATUS_H__ */ diff --git a/src/libmowgli/ext/program_opts.c b/src/libmowgli/ext/program_opts.c new file mode 100644 index 0000000..75acd53 --- /dev/null +++ b/src/libmowgli/ext/program_opts.c @@ -0,0 +1,191 @@ +/* + * libmowgli: A collection of useful routines for programming. + * program_opts.h: Replacement for GNU getopt(). + * + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#include "ext/getopt_long.h" + +void +mowgli_program_opts_consumer_str(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(char **) userdata = mowgli_strdup(arg); +} + +void +mowgli_program_opts_consumer_int(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(int *) userdata = atoi(arg); +} + +void +mowgli_program_opts_consumer_bool(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(bool *) userdata = true; +} + +static inline mowgli_program_opts_t * +mowgli_program_opts_lookup_name(mowgli_program_opts_t *opts, size_t opts_size, const char *name) +{ + size_t i; + + if (strlen(name) > 1) + { + for (i = 0; i < opts_size; i++) + { + if (!strcasecmp(name, opts[i].longopt)) + return &opts[i]; + } + } + else + { + for (i = 0; i < opts_size; i++) + { + if (*name == opts[i].smallopt) + return &opts[i]; + } + } + + return NULL; +} + +static inline mowgli_getopt_option_t * +mowgli_program_opts_convert(const mowgli_program_opts_t *opts, size_t opts_size) +{ + mowgli_getopt_option_t *g_opts; + size_t i; + + return_val_if_fail(opts != NULL, NULL); + + g_opts = mowgli_alloc_array(sizeof(mowgli_getopt_option_t), opts_size); + + for (i = 0; i < opts_size; i++) + { + if (opts[i].longopt == NULL) + continue; + + g_opts[i].name = opts[i].longopt; + g_opts[i].iflag = i; + if (opts[i].has_param) + g_opts[i].has_arg = 1; + } + + return g_opts; +} + +static inline const char * +mowgli_program_opts_compute_optstr(const mowgli_program_opts_t *opts, size_t opts_size) +{ + static char buf[256]; + char *p = buf; + size_t i; + + return_val_if_fail(opts != NULL, NULL); + + memset(buf, '\0', sizeof buf); + + for (i = 0; i < opts_size; i++) + { + if (!opts[i].smallopt) + continue; + + *p++ = opts[i].smallopt; + if (opts[i].has_param) + *p++ = ':'; + } + + *p = '\0'; + + return buf; +} + +static inline void +mowgli_program_opts_dispatch(const mowgli_program_opts_t *opt, const char *optarg) +{ + return_if_fail(opt != NULL); + + if (opt->has_param && optarg == NULL) + { + fprintf(stderr, "no optarg for option %s", opt->longopt); + return; + } + + opt->consumer(optarg, opt->userdata); +} + +void +mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv) +{ + mowgli_getopt_option_t *g_opts; + const char *shortops; + int c; + size_t i; + int opt_index; + + return_if_fail(opts != NULL); + return_if_fail(opts_size > 0); + return_if_fail(argc != NULL); + return_if_fail(argv != NULL); + + g_opts = mowgli_program_opts_convert(opts, opts_size); + shortops = mowgli_program_opts_compute_optstr(opts, opts_size); + + for (;;) + { + const mowgli_program_opts_t *opt = NULL; + + c = mowgli_getopt_long(*argc, *argv, shortops, g_opts, &opt_index); + if (c == -1) + break; + + switch (c) + { + case 0: + /* long-option was provided, resolve it. */ + opt = &opts[g_opts[opt_index].iflag]; + break; + default: + for (i = 0; i < opts_size; i++) + { + if (opts[i].smallopt == c) + { + opt = &opts[i]; + break; + } + } + break; + } + + mowgli_program_opts_dispatch(opt, mowgli_optarg); + } + + mowgli_free(g_opts); +} diff --git a/src/libmowgli/mowgli_allocation_policy.h b/src/libmowgli/ext/program_opts.h index 037b8f9..f418b96 100644 --- a/src/libmowgli/mowgli_allocation_policy.h +++ b/src/libmowgli/ext/program_opts.h @@ -1,8 +1,8 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_allocation_policy.h: Allocation policy management. + * program_opts.h: Replacement for GNU getopt(). * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,25 +21,30 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MOWGLI_ALLOCATION_POLICY_H__ -#define __MOWGLI_ALLOCATION_POLICY_H__ +#ifndef __MOWGLI_PROGRAM_OPTS_H__ +#define __MOWGLI_PROGRAM_OPTS_H__ -typedef void *(*mowgli_allocation_func_t)(int size); -typedef void (*mowgli_deallocation_func_t)(void *ptr); +typedef void (*mowgli_program_opts_consumer_t)(const char *arg, void *userdata); typedef struct { - mowgli_object_t parent; - mowgli_allocation_func_t allocate; - mowgli_deallocation_func_t deallocate; -} mowgli_allocation_policy_t; - -void mowgli_allocation_policy_init(void); -mowgli_allocation_policy_t *mowgli_allocation_policy_create(const char *name, - mowgli_allocation_func_t allocator, mowgli_deallocation_func_t deallocator); -mowgli_allocation_policy_t *mowgli_allocation_policy_lookup(const char *name); - -/* for mowgli_alloc, et. al */ -void mowgli_allocator_set_policy(mowgli_allocation_policy_t *policy); -void mowgli_allocator_set_policy_by_name(const char *name); + const char *longopt; + const char smallopt; + bool has_param; + mowgli_program_opts_consumer_t consumer; + void *userdata; + + /* optional data */ + const char *description; + const char *paramname; +} mowgli_program_opts_t; + +/* use when has_param is true */ +extern void mowgli_program_opts_consumer_str(const char *arg, void *userdata); +extern void mowgli_program_opts_consumer_int(const char *arg, void *userdata); + +/* use when has_param is false */ +extern void mowgli_program_opts_consumer_bool(const char *arg, void *userdata); + +extern void mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv); #endif diff --git a/src/libmowgli/linebuf/Makefile b/src/libmowgli/linebuf/Makefile new file mode 100644 index 0000000..00dc853 --- /dev/null +++ b/src/libmowgli/linebuf/Makefile @@ -0,0 +1,15 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_LINEBUF} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_LINEBUF} + +SRCS = linebuf.c + +INCLUDES = linebuf.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/linebuf + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/linebuf/linebuf.c b/src/libmowgli/linebuf/linebuf.c new file mode 100644 index 0000000..8b13040 --- /dev/null +++ b/src/libmowgli/linebuf/linebuf.c @@ -0,0 +1,292 @@ +/* + * libmowgli: A collection of useful routines for programming. + * linebuf.c: Line buffering for the event loop system + * + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_heap_t *linebuf_heap = NULL; + +static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); +static void mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata); +static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf); + +static int mowgli_linebuf_error(mowgli_vio_t *vio); + +mowgli_linebuf_t * +mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata) +{ + mowgli_linebuf_t *linebuf; + + if (linebuf_heap == NULL) + linebuf_heap = mowgli_heap_create(sizeof(mowgli_linebuf_t), 16, BH_NOW); + + linebuf = mowgli_heap_alloc(linebuf_heap); + + linebuf->delim = "\r\n"; /* Sane default */ + linebuf->readline_cb = cb; + + linebuf->flags = 0; + + linebuf->readbuf.buffer = NULL; + linebuf->writebuf.buffer = NULL; + mowgli_linebuf_setbuflen(&(linebuf->readbuf), 65536); + mowgli_linebuf_setbuflen(&(linebuf->writebuf), 65536); + + linebuf->return_normal_strings = true; /* This is generally what you want, but beware of malicious \0's in input data! */ + + linebuf->userdata = userdata; + + linebuf->vio = mowgli_vio_create(linebuf); + + return linebuf; +} + +/* Attach the linebuf instance to the eventloop -- socket must be created first with VIO instance! */ +void mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop) +{ + return_if_fail(eventloop != NULL); + return_if_fail(linebuf != NULL); + return_if_fail(linebuf->vio != NULL); + return_if_fail((linebuf->vio->flags & MOWGLI_VIO_FLAGS_ISCLOSED) == 0); + + mowgli_vio_eventloop_attach(linebuf->vio, eventloop); + mowgli_pollable_setselect(eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); + mowgli_pollable_setselect(eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); + + linebuf->eventloop = eventloop; +} + +void mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf) +{ + mowgli_vio_destroy(linebuf->vio); + + mowgli_free(linebuf->readbuf.buffer); + mowgli_free(linebuf->writebuf.buffer); + mowgli_heap_free(linebuf_heap, linebuf); +} + +void mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen) +{ + return_if_fail(buffer != NULL); + + if (buffer->buffer == NULL) + buffer->buffer = mowgli_alloc(buflen); + else + { + char tmpbuf[buffer->maxbuflen]; + + if (buffer->buflen > 0) + memcpy(tmpbuf, buffer->buffer, buffer->maxbuflen); /* Copy into tmp buffer */ + + /* Free old buffer and reallocate */ + mowgli_free(buffer->buffer); + buffer->buffer = mowgli_alloc(buflen); + + if (buffer->buflen > 0) + /* Copy into new buffer using old buffer size */ + memcpy(buffer->buffer, tmpbuf, buffer->maxbuflen); + } + + buffer->maxbuflen = buflen; +} + +static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *)userdata; + mowgli_linebuf_buf_t *buffer = &(linebuf->readbuf); + void *bufpos; + size_t offset; + int ret; + + if (buffer->maxbuflen - buffer->buflen == 0) + { + linebuf->flags |= MOWGLI_LINEBUF_ERR_READBUF_FULL; + mowgli_linebuf_error(linebuf->vio); + return; + } + + bufpos = buffer->buffer + buffer->buflen; + offset = buffer->maxbuflen - buffer->buflen + 1; + + if ((ret = mowgli_vio_read(linebuf->vio, bufpos, offset)) <= 0) + { + if (linebuf->vio->error.code != MOWGLI_VIO_ERR_NONE) + /* Let's never come back here */ + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, NULL); + return; + } + + /* Le sigh -- stupid edge-triggered interfaces */ + if (mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDREAD)) + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); + + /* Do we want a write for SSL? */ + if (mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDWRITE)) + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); + + buffer->buflen += ret; + mowgli_linebuf_process(linebuf); +} + +static void mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) +{ + mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *)userdata; + mowgli_linebuf_buf_t *buffer = &(linebuf->writebuf); + int ret; + + if ((ret = mowgli_vio_write(linebuf->vio, buffer->buffer, buffer->buflen)) <= 0) + { + if (linebuf->vio->error.code != MOWGLI_VIO_ERR_NONE) + /* If we have a genuine error, we shouldn't come back to this func + * Otherwise we'll try again. */ + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); + return; + } + + buffer->buflen -= ret; + + /* Anything else to write? */ + if (buffer->buflen == 0) + mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); +} + +void mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...) +{ + char buf[linebuf->writebuf.maxbuflen]; + size_t len; + va_list va; + + va_start(va, format); + len = vsnprintf(buf, linebuf->writebuf.maxbuflen - 1, format, va); + va_end(va); + + mowgli_linebuf_write(linebuf, buf, len); +} + +void mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len) +{ + char *ptr = linebuf->writebuf.buffer + linebuf->writebuf.buflen; + int delim_len = strlen(linebuf->delim); + + return_if_fail(len > 0); + return_if_fail(data != NULL); + + if (linebuf->writebuf.buflen + len + delim_len > linebuf->writebuf.maxbuflen) + { + linebuf->flags |= MOWGLI_LINEBUF_ERR_WRITEBUF_FULL; + mowgli_linebuf_error(linebuf->vio); + return; + } + + memcpy((void *)ptr, data, len); + memcpy((void *)(ptr + len), linebuf->delim, delim_len); + + linebuf->writebuf.buflen += len + delim_len; + + /* Schedule our write */ + mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); +} + +static void mowgli_linebuf_process(mowgli_linebuf_t *linebuf) +{ + mowgli_linebuf_buf_t *buffer = &(linebuf->readbuf); + size_t delim_len = strlen(linebuf->delim); + + char *line_start; + char *cptr; + size_t len = 0; + int linecount = 0; + + line_start = cptr = buffer->buffer; + + /* Initalise */ + linebuf->flags &= ~MOWGLI_LINEBUF_LINE_HASNULLCHAR; + + while (len < buffer->buflen) + { + if (memcmp((void *)cptr, linebuf->delim, delim_len) != 0) + { + if (*cptr == '\0') + /* Warn about unexpected null chars in the string */ + linebuf->flags |= MOWGLI_LINEBUF_LINE_HASNULLCHAR; + cptr++; + len++; + continue; + } + + linecount++; + + /* We now have a line */ + if (linebuf->return_normal_strings) + *cptr = '\0'; + + linebuf->readline_cb(linebuf, line_start, cptr - line_start, linebuf->userdata); + + /* Next line starts here; begin scanning and set the start of it */ + len += delim_len; + cptr += delim_len; + line_start = cptr; + + /* Reset this for next line */ + linebuf->flags &= ~MOWGLI_LINEBUF_LINE_HASNULLCHAR; + } + + if (linecount == 0 && (buffer->buflen == buffer->maxbuflen)) + { + /* No more chars will fit in the buffer and we don't have a line + * We're really screwed, let's trigger an error. */ + linebuf->flags |= MOWGLI_LINEBUF_ERR_READBUF_FULL; + mowgli_linebuf_error(linebuf->vio); + return; + } + + if (line_start != cptr) + { + buffer->buflen = cptr - line_start; + memmove(buffer->buffer, line_start, cptr - line_start); + } + else + buffer->buflen = 0; +} + +static int mowgli_linebuf_error(mowgli_vio_t *vio) +{ + mowgli_linebuf_t *linebuf = vio->userdata; + mowgli_vio_error_t *error = &(linebuf->vio->error); + + if (linebuf->flags & MOWGLI_LINEBUF_ERR_READBUF_FULL) + { + error->op = MOWGLI_VIO_ERR_OP_READ; + error->type = MOWGLI_VIO_ERR_CUSTOM; + mowgli_strlcpy(error->string, "Read buffer full", sizeof(error->string)); + } + else if (linebuf->flags & MOWGLI_LINEBUF_ERR_WRITEBUF_FULL) + { + error->op = MOWGLI_VIO_ERR_OP_WRITE; + error->type = MOWGLI_VIO_ERR_CUSTOM; + mowgli_strlcpy(error->string, "Write buffer full", sizeof(error->string)); + } + + /* Pass this up to higher callback */ + return mowgli_vio_error(vio); +} + diff --git a/src/libmowgli/linebuf/linebuf.h b/src/libmowgli/linebuf/linebuf.h new file mode 100644 index 0000000..17c45ea --- /dev/null +++ b/src/libmowgli/linebuf/linebuf.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_LINEBUF_LINEBUF_H__ +#define __MOWGLI_LINEBUF_LINEBUF_H__ + +#include "eventloop/eventloop.h" +#include "vio/vio.h" + +typedef struct _mowgli_linebuf_buf mowgli_linebuf_buf_t; + +typedef void mowgli_linebuf_readline_cb_t(mowgli_linebuf_t *, char *, size_t, void *); + +extern mowgli_linebuf_t * mowgli_linebuf_create(mowgli_linebuf_readline_cb_t *cb, void *userdata); +extern void mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop); +extern void mowgli_linebuf_destroy(mowgli_linebuf_t *linebuf); + +extern void mowgli_linebuf_setbuflen(mowgli_linebuf_buf_t *buffer, size_t buflen); +extern void mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len); +extern void mowgli_linebuf_writef(mowgli_linebuf_t *linebuf, const char *format, ...); + +struct _mowgli_linebuf_buf { + char *buffer; + size_t buflen; + size_t maxbuflen; +}; + +/* Errors */ +#define MOWGLI_LINEBUF_ERR_NONE 0x0000 +#define MOWGLI_LINEBUF_ERR_READBUF_FULL 0x0001 +#define MOWGLI_LINEBUF_ERR_WRITEBUF_FULL 0x0002 + +/* Informative */ +#define MOWGLI_LINEBUF_LINE_HASNULLCHAR 0x0004 + +struct _mowgli_linebuf { + mowgli_linebuf_readline_cb_t *readline_cb; + + mowgli_vio_t *vio; + + const char *delim; + + int flags; + + mowgli_linebuf_buf_t readbuf; + mowgli_linebuf_buf_t writebuf; + + mowgli_eventloop_t *eventloop; + + bool return_normal_strings; + + void *userdata; +}; + +static inline mowgli_vio_t * mowgli_linebuf_get_vio(mowgli_linebuf_t *linebuf) +{ + return_val_if_fail(linebuf != NULL, NULL); + return linebuf->vio; +} + +#endif + diff --git a/src/libmowgli/module/Makefile b/src/libmowgli/module/Makefile new file mode 100644 index 0000000..702ed7c --- /dev/null +++ b/src/libmowgli/module/Makefile @@ -0,0 +1,15 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_MODULE} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_MODULE} + +SRCS = loader_${LIBMOWGLI_OS}.c + +INCLUDES = module.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/module + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/mowgli_module_posix.c b/src/libmowgli/module/loader_posix.c index dd4a25c..f15c38a 100644 --- a/src/libmowgli/mowgli_module_posix.c +++ b/src/libmowgli/module/loader_posix.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_module.c: Loadable modules for POSIX systems. + * loader_posix.c: Loadable modules for POSIX systems. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_module_win32.c b/src/libmowgli/module/loader_win32.c index e4b7428..f42a742 100644 --- a/src/libmowgli/mowgli_module_win32.c +++ b/src/libmowgli/module/loader_win32.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_module_win32.c: Loadable modules under Microsoft Windows. + * loader_win32.c: Loadable modules under Microsoft Windows. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_module.h b/src/libmowgli/module/module.h index 1ef89b4..54fc344 100644 --- a/src/libmowgli/mowgli_module.h +++ b/src/libmowgli/module/module.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_module.h: Loadable modules. + * module.h: Loadable modules. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli.h b/src/libmowgli/mowgli.h index fe494b2..6a64f0d 100644 --- a/src/libmowgli/mowgli.h +++ b/src/libmowgli/mowgli.h @@ -33,47 +33,63 @@ #endif #ifdef MOWGLI_CORE -# include "win32_support.h" -# include "mowgli_config.h" +# include "platform/autoconf.h" #endif -#include "mowgli_stdinc.h" +#include "core/stdinc.h" MOWGLI_DECLS_START -#include "mowgli_logger.h" -#include "mowgli_assert.h" -#include "mowgli_exception.h" -#include "mowgli_iterator.h" - -#include "mowgli_alloc.h" -#include "mowgli_spinlock.h" -#include "mowgli_list.h" -#include "mowgli_object_class.h" -#include "mowgli_object.h" -#include "mowgli_allocation_policy.h" -#include "mowgli_dictionary.h" -#include "mowgli_patricia.h" -#include "mowgli_mempool.h" -#include "mowgli_module.h" -#include "mowgli_queue.h" -#include "mowgli_hash.h" -#include "mowgli_heap.h" -#include "mowgli_init.h" -#include "mowgli_bitvector.h" -#include "mowgli_hook.h" -#include "mowgli_signal.h" -#include "mowgli_error_backtrace.h" -#include "mowgli_random.h" -#include "mowgli_ioevent.h" -#include "mowgli_argstack.h" -#include "mowgli_object_messaging.h" -#include "mowgli_object_metadata.h" -#include "mowgli_global_storage.h" -#include "mowgli_string.h" -#include "mowgli_allocator.h" -#include "mowgli_formatter.h" -#include "mowgli_index.h" +#include "platform/constructor.h" +#include "platform/machine.h" + +#include "core/logger.h" +#include "core/assert.h" +#include "core/exception.h" +#include "core/iterator.h" + +#include "container/list.h" +#include "object/class.h" +#include "object/object.h" + +#include "core/allocation_policy.h" +#include "core/alloc.h" + +#include "container/dictionary.h" + +#include "thread/thread.h" +#include "thread/mutex.h" + +#include "base/memslice.h" +#include "container/patricia.h" +#include "module/module.h" +#include "container/queue.h" +#include "base/hash.h" +#include "core/heap.h" +#include "core/bootstrap.h" +#include "base/bitvector.h" +#include "base/hook.h" +#include "base/mowgli_signal.h" +#include "ext/proctitle.h" +#include "ext/error_backtrace.h" +#include "base/random.h" +#include "base/argstack.h" +#include "object/message.h" +#include "object/metadata.h" +#include "ext/global_storage.h" +#include "core/process.h" +#include "eventloop/eventloop.h" +#include "vio/vio.h" +#include "core/mowgli_string.h" +#include "core/allocator.h" +#include "base/formatter.h" +#include "container/index.h" + +#include "ext/confparse.h" +#include "ext/program_opts.h" + +#include "linebuf/linebuf.h" +#include "dns/dns.h" MOWGLI_DECLS_END diff --git a/src/libmowgli/mowgli_alloc.c b/src/libmowgli/mowgli_alloc.c deleted file mode 100644 index c7d3c4f..0000000 --- a/src/libmowgli/mowgli_alloc.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_alloc.c: Safe, portable implementations of malloc, calloc, and free. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -/* - * bootstrapped allocators so that we can initialise without blowing up - */ - -static void * -_mowgli_bootstrap_alloc(int size) -{ - return calloc(size, 1); -} - -static void -_mowgli_bootstrap_free(void *ptr) -{ - if (ptr) - free(ptr); -} - -static mowgli_allocation_policy_t _mowgli_allocator_bootstrap = { - { 0 }, - _mowgli_bootstrap_alloc, - _mowgli_bootstrap_free -}; - -static mowgli_allocation_policy_t *_mowgli_allocator = &_mowgli_allocator_bootstrap; - -/* - * \brief Allocates an array of data that contains "count" objects, - * of "size" size. - * - * Usually, this wraps calloc(). - * - * \param size size of objects to allocate. - * \param count amount of objects to allocate. - * - * \return A pointer to a memory buffer. - */ -void * -mowgli_alloc_array(size_t size, size_t count) -{ - return_val_if_fail(_mowgli_allocator != NULL, NULL); - - return _mowgli_allocator->allocate(size * count); -} - -/* - * \brief Allocates an object of "size" size. - * - * This is the equivilant of calling mowgli_alloc_array(size, 1). - * - * \param size size of object to allocate. - * - * \return A pointer to a memory buffer. - */ -void * -mowgli_alloc(size_t size) -{ - return mowgli_alloc_array(size, 1); -} - -/* - * \brief Frees an object back to the system memory pool. - * - * Wraps free protecting against common mistakes (reports an error instead). - * - * \param ptr pointer to object to free. - */ -void -mowgli_free(void *ptr) -{ - return_if_fail(_mowgli_allocator != NULL); - return_if_fail(ptr != NULL); - - _mowgli_allocator->deallocate(ptr); -} - -/* - * \brief Sets the mowgli.allocation_policy used by the allocation primitives. - * - * \param policy The mowgli_allocation_policy_t object to use. - */ -void -mowgli_allocator_set_policy(mowgli_allocation_policy_t *policy) -{ - return_if_fail(policy != NULL); - - _mowgli_allocator = policy; -} - -/* - * \brief Sets the mowgli.allocation_policy used by the allocation primitives, - * when given a name. - * - * \param name The name of the policy to use. - */ -void -mowgli_allocator_set_policy_by_name(const char *name) -{ - mowgli_allocation_policy_t *policy; - - return_if_fail(name != NULL); - - policy = mowgli_allocation_policy_lookup(name); - - if (policy == NULL) - return; - - mowgli_allocator_set_policy(policy); -} diff --git a/src/libmowgli/mowgli_alloc.h b/src/libmowgli/mowgli_alloc.h deleted file mode 100644 index 16bd674..0000000 --- a/src/libmowgli/mowgli_alloc.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_alloc.h: Safe, portable implementations of malloc, calloc, and free. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_ALLOC_H__ -#define __MOWGLI_ALLOC_H__ - -extern void * mowgli_alloc_array(size_t size, size_t count); -extern void * mowgli_alloc(size_t size); -extern void mowgli_free(void *ptr); - -#endif diff --git a/src/libmowgli/mowgli_allocation_policy.c b/src/libmowgli/mowgli_allocation_policy.c deleted file mode 100644 index 8f390d1..0000000 --- a/src/libmowgli/mowgli_allocation_policy.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_allocation_policy.h: Allocation policy management. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -static mowgli_object_class_t klass; -static mowgli_patricia_t *mowgli_allocation_policy_dict = NULL; - -static void _allocation_policy_key_canon(char *str) -{ - -} - -void -mowgli_allocation_policy_init(void) -{ - mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); - - mowgli_object_class_init(&klass, "mowgli.allocation_policy", NULL, FALSE); -} - -mowgli_allocation_policy_t * -mowgli_allocation_policy_create(const char *name, mowgli_allocation_func_t allocator, - mowgli_deallocation_func_t deallocator) -{ - mowgli_allocation_policy_t *policy; - - if (mowgli_allocation_policy_dict == NULL) - mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); - - if ((policy = mowgli_patricia_retrieve(mowgli_allocation_policy_dict, name))) - return policy; - - policy = mowgli_alloc(sizeof(mowgli_allocation_policy_t)); - mowgli_object_init_from_class(mowgli_object(policy), name, &klass); - - policy->allocate = allocator; - policy->deallocate = deallocator; - - return policy; -} - -mowgli_allocation_policy_t * -mowgli_allocation_policy_lookup(const char *name) -{ - if (mowgli_allocation_policy_dict == NULL) - mowgli_allocation_policy_dict = mowgli_patricia_create(_allocation_policy_key_canon); - - return mowgli_patricia_retrieve(mowgli_allocation_policy_dict, name); -} diff --git a/src/libmowgli/mowgli_assert.h b/src/libmowgli/mowgli_assert.h deleted file mode 100644 index 8ee2c4f..0000000 --- a/src/libmowgli/mowgli_assert.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_assert.h: Assertions. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_ASSERT_H__ -#define __MOWGLI_ASSERT_H__ - -extern void mowgli_soft_assert_log(const char *asrt, const char *file, int line, const char *function); - -#ifdef __GNUC__ - -/* - * Performs a soft assertion. If the assertion fails, we log it. - */ -#define soft_assert(x) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } - -/* - * Same as soft_assert, but returns if an assertion fails. - */ -#define return_if_fail(x) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return; \ - } - -/* - * Same as soft_assert, but returns a given value if an assertion fails. - */ -#define return_val_if_fail(x, y) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return (y); \ - } - -/* - * Same as soft_assert, but returns NULL if the value is NULL. - */ -#define return_if_null(x) \ - if (x == NULL) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return (NULL); \ - } - -#else - -/* - * Performs a soft assertion. If the assertion fails, we log it. - */ -#define soft_assert(x) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ - } - -/* - * Same as soft_assert, but returns if an assertion fails. - */ -#define return_if_fail(x) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ - return; \ - } - -/* - * Same as soft_assert, but returns a given value if an assertion fails. - */ -#define return_val_if_fail(x, y) \ - if (!(x)) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ - return (y); \ - } - -/* - * Same as soft_assert, but returns NULL if the value is NULL. - */ -#define return_if_null(x) \ - if (x == NULL) { \ - mowgli_soft_assert_log(#x, __FILE__, __LINE__, __FUNCTION__); \ - return (NULL); \ - } - -#endif - -#endif diff --git a/src/libmowgli/mowgli_config.h.in b/src/libmowgli/mowgli_config.h.in deleted file mode 100644 index c43e92c..0000000 --- a/src/libmowgli/mowgli_config.h.in +++ /dev/null @@ -1,147 +0,0 @@ -/* src/libmowgli/mowgli_config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to 1 if the `closedir' function returns void instead of `int'. */ -#undef CLOSEDIR_VOID - -/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. - */ -#undef HAVE_DIRENT_H - -/* Define to 1 if you have the `epoll_ctl' function. */ -#undef HAVE_EPOLL_CTL - -/* Define to 1 if you have the <errno.h> header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the <inttypes.h> header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the <limits.h> header file. */ -#undef HAVE_LIMITS_H - -/* Define to 1 if you have the <locale.h> header file. */ -#undef HAVE_LOCALE_H - -/* Define to 1 if you have the <memory.h> header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET - -/* Define to 1 if you have the `mmap' function. */ -#undef HAVE_MMAP - -/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ -#undef HAVE_NDIR_H - -/* Define to 1 if you have the `port_create' function. */ -#undef HAVE_PORT_CREATE - -/* Define to 1 if you have the `printf' function. */ -#undef HAVE_PRINTF - -/* Define to 1 if you have the `setlocale' function. */ -#undef HAVE_SETLOCALE - -/* Define to 1 if you have the `snprintf' function. */ -#undef HAVE_SNPRINTF - -/* Define to 1 if you have the `sprintf' function. */ -#undef HAVE_SPRINTF - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -#undef HAVE_STAT_EMPTY_STRING_BUG - -/* Define to 1 if you have the <stdarg.h> header file. */ -#undef HAVE_STDARG_H - -/* Define to 1 if you have the <stdint.h> header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the <stdlib.h> header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - -/* Define to 1 if you have the <strings.h> header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the <string.h> header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strlcat' function. */ -#undef HAVE_STRLCAT - -/* Define to 1 if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - -/* Define to 1 if you have the `strndup' function. */ -#undef HAVE_STRNDUP - -/* Define to 1 if you have the `strtod' function. */ -#undef HAVE_STRTOD - -/* Define to 1 if you have the `strtol' function. */ -#undef HAVE_STRTOL - -/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. - */ -#undef HAVE_SYS_DIR_H - -/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. - */ -#undef HAVE_SYS_NDIR_H - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the <sys/types.h> header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the <unistd.h> header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the `vsnprintf' function. */ -#undef HAVE_VSNPRINTF - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -#undef LSTAT_FOLLOWS_SLASHED_SYMLINK - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const diff --git a/src/libmowgli/mowgli_exception.h b/src/libmowgli/mowgli_exception.h deleted file mode 100644 index c919bcb..0000000 --- a/src/libmowgli/mowgli_exception.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_exception.h: Exceptions. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_EXCEPTION_H__ -#define __MOWGLI_EXCEPTION_H__ - -#define mowgli_throw_exception(x) do { mowgli_log("exception %s thrown", #x); return; } while(0) - -#define mowgli_throw_exception_val(x, y) do { mowgli_log("exception %s thrown", #x); return (y); } while(0) - -#define mowgli_throw_exception_fatal(x) \ - do { \ - mowgli_log("exception %s thrown", #x); \ - exit(EXIT_FAILURE); \ - } while (0) - -#endif diff --git a/src/libmowgli/mowgli_heap.c b/src/libmowgli/mowgli_heap.c deleted file mode 100644 index 532517a..0000000 --- a/src/libmowgli/mowgli_heap.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_heap.c: Heap allocation. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * Copyright (c) 2005-2006 Theo Julienne <terminal -at- atheme.org> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Legal note: code devised from claro.base.block module r288 (Pre MPL) - */ - -#include "mowgli.h" - -#ifdef HAVE_MMAP -# include <sys/mman.h> -# if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) -# define MAP_ANON MAP_ANONYMOUS -# endif -#endif - -/* A block of memory allocated to the allocator */ -struct mowgli_block_ -{ - mowgli_node_t node; - - /* link back to our heap */ - mowgli_heap_t *heap; - - /* pointer to the first item */ - void *data; - - /* singly linked list of free items */ - void *first_free; - - int num_allocated; -}; - -/* A pile of blocks */ -struct mowgli_heap_ -{ - mowgli_node_t node; - - unsigned int elem_size; - unsigned int mowgli_heap_elems; - unsigned int free_elems; - - unsigned int alloc_size; - - unsigned int flags; - - mowgli_list_t blocks; /* list of non-empty blocks */ - - mowgli_allocation_policy_t *allocator; - mowgli_boolean_t use_mmap; - - mowgli_block_t *empty_block; /* a single entirely free block, or NULL */ -}; - -typedef struct mowgli_heap_elem_header_ mowgli_heap_elem_header_t; - -struct mowgli_heap_elem_header_ -{ - union - { - mowgli_block_t *block; /* for allocated elems: block ptr */ - mowgli_heap_elem_header_t *next; /* for free elems: next free */ - } un; -}; - -/* expands a mowgli_heap_t by 1 block */ -static void -mowgli_heap_expand(mowgli_heap_t *bh) -{ - mowgli_block_t *block = NULL; - void *blp = NULL; - mowgli_heap_elem_header_t *node, *prev; - char *offset; - unsigned int a; - - size_t blp_size = sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems); - - return_if_fail(bh->empty_block == NULL); - -#if defined(HAVE_MMAP) && defined(MAP_ANON) - if (bh->use_mmap) - blp = mmap(NULL, sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems), - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - else -#endif - { - if (bh->allocator) - blp = bh->allocator->allocate(blp_size); - else - blp = mowgli_alloc(blp_size); - } - - block = (mowgli_block_t *)blp; - - offset = (char*)blp + sizeof(mowgli_block_t); - block->data = offset; - block->heap = bh; - - prev = NULL; - - for (a = 0; a < bh->mowgli_heap_elems; a++) - { - node = (mowgli_heap_elem_header_t *)offset; - node->un.next = prev; - offset += bh->alloc_size; - prev = node; - } - - block->first_free = prev; - - bh->empty_block = block; - bh->free_elems += bh->mowgli_heap_elems; -} - -/* shrinks a mowgli_heap_t by 1 block. */ -static void -mowgli_heap_shrink(mowgli_heap_t *heap, mowgli_block_t *b) -{ - return_if_fail(b != NULL); - - if (b == heap->empty_block) - heap->empty_block = NULL; - else - mowgli_node_delete(&b->node, &heap->blocks); - -#ifdef HAVE_MMAP - if (heap->use_mmap) - munmap(b, sizeof(mowgli_block_t) + (heap->alloc_size * heap->mowgli_heap_elems)); - else -#endif - if (heap->allocator) - heap->allocator->deallocate(b); - else - mowgli_free(b); - - heap->free_elems -= heap->mowgli_heap_elems; -} - -/* creates a new mowgli_heap_t */ -mowgli_heap_t * -mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, - mowgli_allocation_policy_t *allocator) -{ - mowgli_heap_t *bh = mowgli_alloc(sizeof(mowgli_heap_t)); - int numpages, pagesize; - - bh->elem_size = elem_size; - bh->mowgli_heap_elems = mowgli_heap_elems; - /* at least 2, this avoids some silly special cases */ - if (bh->mowgli_heap_elems < 2) - bh->mowgli_heap_elems = 2; - bh->free_elems = 0; - - bh->alloc_size = bh->elem_size + sizeof(mowgli_heap_elem_header_t); - - /* don't waste part of a page */ - if (allocator == NULL) - { -#ifdef HAVE_MMAP - pagesize = getpagesize(); -#else - pagesize = 4096; -#endif - numpages = (sizeof(mowgli_block_t) + (bh->alloc_size * bh->mowgli_heap_elems) + pagesize - 1) / pagesize; - bh->mowgli_heap_elems = (numpages * pagesize - sizeof(mowgli_block_t)) / bh->alloc_size; - } - - bh->flags = flags; - - bh->allocator = allocator ? allocator : mowgli_allocator_malloc; - -#ifdef HAVE_MMAP - bh->use_mmap = allocator != NULL ? FALSE : TRUE; -#endif - - if (flags & BH_NOW) - mowgli_heap_expand(bh); - - return bh; -} - -mowgli_heap_t * -mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags) -{ - return mowgli_heap_create_full(elem_size, mowgli_heap_elems, flags, NULL); -} - -/* completely frees a mowgli_heap_t and all blocks */ -void -mowgli_heap_destroy(mowgli_heap_t *heap) -{ - mowgli_node_t *n, *tn; - - MOWGLI_LIST_FOREACH_SAFE(n, tn, heap->blocks.head) - { - mowgli_heap_shrink(heap, n->data); - } - if (heap->empty_block) - mowgli_heap_shrink(heap, heap->empty_block); - - /* everything related to heap has gone, time for itself */ - mowgli_free(heap); -} - -/* allocates a new item from a mowgli_heap_t */ -void * -mowgli_heap_alloc(mowgli_heap_t *heap) -{ - mowgli_node_t *n; - mowgli_block_t *b; - mowgli_heap_elem_header_t *h; - - /* no free space? */ - if (heap->free_elems == 0) - { - mowgli_heap_expand(heap); - - return_val_if_fail(heap->free_elems != 0, NULL); - } - - /* try a partially used block before using a fully free block */ - n = heap->blocks.head; - b = n != NULL ? n->data : NULL; - if (b == NULL || b->first_free == NULL) - b = heap->empty_block; - /* due to above check */ - return_val_if_fail(b != NULL, NULL); - - /* pull the first free node from the list */ - h = b->first_free; - return_val_if_fail(h != NULL, NULL); - - /* mark it as used */ - b->first_free = h->un.next; - h->un.block = b; - - /* keep count */ - heap->free_elems--; - b->num_allocated++; - - /* move it between the lists if needed */ - /* note that a block has at least two items in it, so these cases - * cannot both occur in the same allocation */ - if (b->num_allocated == 1) - { - heap->empty_block = NULL; - mowgli_node_add_head(b, &b->node, &heap->blocks); - } - else if (b->first_free == NULL) - { - /* move full blocks to the end of the list */ - mowgli_node_delete(&b->node, &heap->blocks); - mowgli_node_add(b, &b->node, &heap->blocks); - } - -#ifdef HEAP_DEBUG - /* debug */ - mowgli_log("mowgli_heap_alloc(heap = @%p) -> %p", heap, fn->data); -#endif - /* return pointer to it */ - return (char *)h + sizeof(mowgli_heap_elem_header_t); -} - -/* frees an item back to the mowgli_heap_t */ -void -mowgli_heap_free(mowgli_heap_t *heap, void *data) -{ - mowgli_block_t *b; - mowgli_heap_elem_header_t *h; - - h = (mowgli_heap_elem_header_t *)((char *)data - sizeof(mowgli_heap_elem_header_t)); - b = h->un.block; - - return_if_fail(b->heap == heap); - return_if_fail(b->num_allocated > 0); - - /* memset the element before returning it to the heap. */ - memset(data, 0, b->heap->elem_size); - - /* mark it as free */ - h->un.next = b->first_free; - b->first_free = h; - - /* keep count */ - heap->free_elems++; - b->num_allocated--; -#ifdef HEAP_DEBUG - /* debug */ - mowgli_log("mowgli_heap_free(heap = @%p, data = %p)", heap, data); -#endif - /* move it between the lists if needed */ - if (b->num_allocated == 0) - { - if (heap->empty_block != NULL) - mowgli_heap_shrink(heap, heap->empty_block); - mowgli_node_delete(&b->node, &heap->blocks); - heap->empty_block = b; - } - else if (b->num_allocated == heap->mowgli_heap_elems - 1) - { - mowgli_node_delete(&b->node, &heap->blocks); - mowgli_node_add_head(b, &b->node, &heap->blocks); - } -} diff --git a/src/libmowgli/mowgli_heap.h b/src/libmowgli/mowgli_heap.h deleted file mode 100644 index 8a38f55..0000000 --- a/src/libmowgli/mowgli_heap.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_heap.h: Heap allocation. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * Copyright (c) 2005-2006 Theo Julienne <terminal -at- atheme.org> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Legal note: code devised from claro.base.block module r288 (Pre MPL) - */ - -#ifndef __MOWGLI_HEAP_H__ -#define __MOWGLI_HEAP_H__ - -typedef struct mowgli_heap_ mowgli_heap_t; -typedef struct mowgli_block_ mowgli_block_t; - -/* Flag for mowgli_heap_create */ -#define BH_DONTCARE 0 - -#define BH_NOW 1 -#define BH_LAZY 0 - -/* Functions for heaps */ -extern mowgli_heap_t *mowgli_heap_create(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags); -extern mowgli_heap_t *mowgli_heap_create_full(size_t elem_size, size_t mowgli_heap_elems, unsigned int flags, - mowgli_allocation_policy_t *allocator); -extern void mowgli_heap_destroy(mowgli_heap_t *heap); - -/* Functions for blocks */ -extern void *mowgli_heap_alloc(mowgli_heap_t *heap); -extern void mowgli_heap_free(mowgli_heap_t *heap, void *data); - -#endif - diff --git a/src/libmowgli/mowgli_init.c b/src/libmowgli/mowgli_init.c deleted file mode 100644 index 5b15aa0..0000000 --- a/src/libmowgli/mowgli_init.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_init.c: Initialization of libmowgli. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -void mowgli_init(void) -{ - static int mowgli_initted_ = 0; - - if (mowgli_initted_) - return; - - /* initial bootstrap */ - mowgli_node_init(); - mowgli_queue_init(); - mowgli_argstack_init(); - mowgli_bitvector_init(); - mowgli_global_storage_init(); - mowgli_hook_init(); - mowgli_random_init(); - mowgli_allocation_policy_init(); - mowgli_allocator_init(); - - /* now that we're bootstrapped, we can use a more optimised allocator - if one is available. */ - mowgli_allocator_set_policy(mowgli_allocator_malloc); - - mowgli_initted_++; -} diff --git a/src/libmowgli/mowgli_ioevent.c b/src/libmowgli/mowgli_ioevent.c deleted file mode 100644 index ed08cb9..0000000 --- a/src/libmowgli/mowgli_ioevent.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_ioevent.c: Portable I/O event layer. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -#ifdef HAVE_EPOLL_CTL -# include <sys/epoll.h> -#endif - -#ifdef HAVE_PORT_CREATE -# include <port.h> -#endif - -mowgli_ioevent_handle_t *mowgli_ioevent_create(void) -{ - mowgli_ioevent_handle_t *self = mowgli_alloc(sizeof(mowgli_ioevent_handle_t)); - -#ifdef HAVE_EPOLL_CTL - self->impldata = epoll_create(FD_SETSIZE); -#endif - -#ifdef HAVE_PORT_CREATE - self->impldata = port_create(); -#endif - - return self; -} - -void mowgli_ioevent_destroy(mowgli_ioevent_handle_t *self) -{ - return_if_fail(self != NULL); - -#if defined(HAVE_EPOLL_CTL) || defined(HAVE_PORT_CREATE) - close(self->impldata); -#endif - - mowgli_free(self); -} - -int mowgli_ioevent_get(mowgli_ioevent_handle_t *self, mowgli_ioevent_t *buf, size_t bufsize, unsigned int delay) -{ -#if defined HAVE_EPOLL_CTL || defined HAVE_PORT_CREATE - int ret, iter; -#else - int ret = -1; -#endif - -#ifdef HAVE_EPOLL_CTL - struct epoll_event events[bufsize]; - - ret = epoll_wait(self->impldata, events, bufsize, delay); - - if (ret == -1) - return ret; - - for (iter = 0; iter < ret; iter++) - { - buf[iter].ev_status = 0; - buf[iter].ev_object = events[iter].data.fd; - buf[iter].ev_opaque = events[iter].data.ptr; - buf[iter].ev_source = MOWGLI_SOURCE_FD; - - if (events[iter].events & EPOLLIN) - buf[iter].ev_status |= MOWGLI_POLLRDNORM; - - if (events[iter].events & EPOLLOUT) - buf[iter].ev_status |= MOWGLI_POLLWRNORM; - - if (events[iter].events & EPOLLHUP) - buf[iter].ev_status = MOWGLI_POLLHUP; - - if (events[iter].events & EPOLLERR) - buf[iter].ev_status = MOWGLI_POLLERR; - } -#endif - -#ifdef HAVE_PORT_CREATE - port_event_t events[bufsize]; - unsigned int nget = 1; - struct timespec poll_time; - - poll_time.tv_sec = delay / 1000; - poll_time.tv_nsec = (delay % 1000) * 1000000; - - ret = port_getn(self->impldata, events, bufsize, &nget, &poll_time); - - if (ret == -1) - return ret; - - for (iter = 0; iter < nget; iter++) - { - buf[iter].ev_status = 0; - buf[iter].ev_object = events[iter].portev_object; - buf[iter].ev_opaque = events[iter].portev_user; - buf[iter].ev_source = MOWGLI_SOURCE_FD; - - if (events[iter].portev_events & POLLRDNORM) - buf[iter].ev_status |= MOWGLI_POLLRDNORM; - - if (events[iter].portev_events & POLLWRNORM) - buf[iter].ev_status |= MOWGLI_POLLWRNORM; - - if (events[iter].portev_events & POLLHUP) - buf[iter].ev_status = MOWGLI_POLLHUP; - - if (events[iter].portev_events & POLLERR) - buf[iter].ev_status = MOWGLI_POLLERR; - } - - ret = nget; -#endif - - return ret; -} - -void mowgli_ioevent_associate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object, unsigned int flags, void *opaque) -{ -#if defined HAVE_EPOLL_CTL || defined HAVE_PORT_CREATE - int events = 0; -#endif - - if (source != MOWGLI_SOURCE_FD) - return; - -#ifdef HAVE_EPOLL_CTL - { - struct epoll_event ep_event = {}; - events = EPOLLONESHOT; - - if (flags & MOWGLI_POLLRDNORM) - events |= EPOLLIN; - - if (flags & MOWGLI_POLLWRNORM) - events |= EPOLLOUT; - - ep_event.events = events; - ep_event.data.ptr = opaque; - - epoll_ctl(self->impldata, EPOLL_CTL_ADD, object, &ep_event); - } -#endif - -#ifdef HAVE_PORT_CREATE -#ifdef POLLRDNORM - if (flags & MOWGLI_POLLRDNORM) - events |= POLLRDNORM; -#endif - -#ifdef EPOLLWRNORM - if (flags & MOWGLI_POLLWRNORM) - events |= EPOLLWRNORM; -#endif - - port_associate(self->impldata, PORT_SOURCE_FD, object, events, opaque); -#endif -} - -void mowgli_ioevent_dissociate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object) -{ - if (source != MOWGLI_SOURCE_FD) - return; - -#ifdef HAVE_EPOLL_CTL - { - struct epoll_event ep_event = {}; - - epoll_ctl(self->impldata, EPOLL_CTL_DEL, object, &ep_event); - } -#endif - -#ifdef HAVE_PORT_CREATE - port_dissociate(self->impldata, PORT_SOURCE_FD, object); -#endif -} - diff --git a/src/libmowgli/mowgli_ioevent.h b/src/libmowgli/mowgli_ioevent.h deleted file mode 100644 index 17007b6..0000000 --- a/src/libmowgli/mowgli_ioevent.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_ioevent.h: Portable I/O event layer. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_IOEVENT_H__ -#define __MOWGLI_IOEVENT_H__ - -typedef struct { - int impldata; /* implementation-specific data: this is almost always an FD */ -} mowgli_ioevent_handle_t; - -typedef enum { - MOWGLI_SOURCE_FD = 1 -} mowgli_ioevent_source_t; - -typedef struct { - mowgli_ioevent_source_t ev_source; - unsigned int ev_status; - int ev_object; - void *ev_opaque; -} mowgli_ioevent_t; - -#define MOWGLI_POLLRDNORM 0x01 -#define MOWGLI_POLLWRNORM 0x02 -#define MOWGLI_POLLHUP 0x04 -#define MOWGLI_POLLERR 0x08 - -extern mowgli_ioevent_handle_t *mowgli_ioevent_create(void) MOWGLI_DEPRECATED; -extern void mowgli_ioevent_destroy(mowgli_ioevent_handle_t *self) MOWGLI_DEPRECATED; - -extern int mowgli_ioevent_get(mowgli_ioevent_handle_t *self, mowgli_ioevent_t *buf, size_t bufsize, unsigned int delay) MOWGLI_DEPRECATED; - -extern void mowgli_ioevent_associate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object, unsigned int flags, void *opaque) MOWGLI_DEPRECATED; -extern void mowgli_ioevent_dissociate(mowgli_ioevent_handle_t *self, mowgli_ioevent_source_t source, int object) MOWGLI_DEPRECATED; - -#endif diff --git a/src/libmowgli/mowgli_iterator.h b/src/libmowgli/mowgli_iterator.h deleted file mode 100644 index f99412b..0000000 --- a/src/libmowgli/mowgli_iterator.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_iterator.h: Iterators. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_ITERATOR_H__ -#define __MOWGLI_ITERATOR_H__ - -typedef struct _mowgli_iterator { - struct _mowgli_iterator *prev, *next; - void *data; -} mowgli_iterator_t; - -/* The following are macros which can be used with iterators. */ -#define MOWGLI_ITER_FOREACH(n, head) for (n = (head); n; n = n->next) -#define MOWGLI_ITER_FOREACH_NEXT(n, head) for (n = (head); n->next; n = n->next) -#define MOWGLI_ITER_FOREACH_PREV(n, tail) for (n = (tail); n; n = n->prev) -#define MOWGLI_ITER_FOREACH_SAFE(n, tn, head) for (n = (head), tn = n ? n->next : NULL; n != NULL; n = tn, tn = n ? n->next : NULL) - -#endif diff --git a/src/libmowgli/mowgli_logger.c b/src/libmowgli/mowgli_logger.c deleted file mode 100644 index e3c13ea..0000000 --- a/src/libmowgli/mowgli_logger.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_logger.c: Event and debugging message logging. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -void mowgli_log_cb_default(const char *buf) -{ - fprintf(stderr, "%s\n", buf); -} - -static mowgli_log_cb_t mowgli_log_cb = mowgli_log_cb_default; - -void mowgli_log_real(const char *file, int line, const char *func, const char *fmt, ...) -{ - char buf[65535]; - char snbuf[65535]; - va_list va; - - va_start(va, fmt); - vsnprintf(snbuf, 65535, fmt, va); - va_end(va); - - snprintf(buf, 65535, "(%s:%d) [%s]: %s", file, line, func, snbuf); - - mowgli_log_cb(buf); -} - -void mowgli_log_set_cb(mowgli_log_cb_t callback) -{ - return_if_fail(callback != NULL); - - mowgli_log_cb = callback; -} - -void mowgli_soft_assert_log(const char *asrt, const char *file, int line, const char *function) -{ - char buf[65535]; - - snprintf(buf, sizeof buf, "(%s:%d) [%s]: critical: Assertion '%s' failed.", file, line, function, asrt); - - mowgli_log_cb(buf); -} diff --git a/src/libmowgli/mowgli_mempool.c b/src/libmowgli/mowgli_mempool.c deleted file mode 100644 index c41436c..0000000 --- a/src/libmowgli/mowgli_mempool.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_mempool.c: Memory pooling. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -/* visibility of this object is not available to the outside */ -struct mowgli_mempool_t_ { - mowgli_list_t stack; - mowgli_destructor_t destructor; -#ifdef NOTYET - mowgli_mutex_t *mutex; -#endif -}; - -typedef struct { - void *addr; - int refcount; - mowgli_node_t node; -} mowgli_mempool_elem_t; - -mowgli_mempool_t *mowgli_mempool_with_custom_destructor(mowgli_destructor_t destructor) -{ - mowgli_mempool_t *pool; - - pool = mowgli_alloc(sizeof(mowgli_mempool_t)); - pool->destructor = destructor; -#ifdef NOTYET - pool->mutex = mowgli_mutex_create(); -#endif - return pool; -} - -mowgli_mempool_t *mowgli_mempool_create(void) -{ - return mowgli_mempool_with_custom_destructor(mowgli_free); -} - -void *mowgli_mempool_add(mowgli_mempool_t * pool, void * ptr) -{ - mowgli_mempool_elem_t *e = mowgli_alloc(sizeof(mowgli_mempool_elem_t)); - - e->addr = ptr; - e->refcount = 1; - -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - mowgli_node_add(e, &e->node, &pool->stack); -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); -#endif - return ptr; -} - -void * -mowgli_mempool_allocate(mowgli_mempool_t * pool, size_t sz) -{ - void * addr; - -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - addr = mowgli_alloc(sz); - mowgli_node_add(addr, mowgli_node_create(), &pool->stack); -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); -#endif - return addr; -} - -void -mowgli_mempool_sustain(mowgli_mempool_t * pool, void * addr) -{ - mowgli_node_t *n, *tn; - mowgli_mempool_elem_t *e; - -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - - MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) - { - e = (mowgli_mempool_elem_t *) n->data; - - if (e->addr == addr) - ++e->refcount; - } - -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); -#endif -} - -void -mowgli_mempool_release(mowgli_mempool_t * pool, void * addr) -{ - mowgli_node_t *n, *tn; - mowgli_mempool_elem_t *e; - -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - - MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) - { - e = (mowgli_mempool_elem_t *) n->data; - - if (e->addr == addr && --e->refcount == 0) - { - mowgli_node_delete(n, &pool->stack); - pool->destructor(addr); - mowgli_free(e); - } - } - -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); -#endif -} - -static void -mowgli_mempool_cleanup_nolock(mowgli_mempool_t * pool) -{ - mowgli_node_t *n, *tn; - - MOWGLI_LIST_FOREACH_SAFE(n, tn, pool->stack.head) - { - mowgli_mempool_elem_t *e = (mowgli_mempool_elem_t *) n->data; - - /* don't care about refcounting here. we're killing the entire pool. */ - mowgli_log("mowgli_mempool_t<%p> element at %p was not released until cleanup (refcount: %d)", pool, e->addr, e->refcount); - pool->destructor(e->addr); - mowgli_free(e); - - mowgli_node_delete(n, &pool->stack); - } -} - -void -mowgli_mempool_cleanup(mowgli_mempool_t * pool) -{ -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - mowgli_mempool_cleanup_nolock(pool); -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); -#endif -} - -void -mowgli_mempool_destroy(mowgli_mempool_t * pool) -{ -#ifdef NOTYET - mowgli_mutex_lock(pool->mutex); -#endif - - mowgli_mempool_cleanup_nolock(pool); - -#ifdef NOTYET - mowgli_mutex_unlock(pool->mutex); - - mowgli_mutex_free(pool->mutex); -#endif - - mowgli_free(pool); -} - -char * -mowgli_mempool_strdup(mowgli_mempool_t * pool, char * src) -{ - char *out; - size_t sz = strlen(src) + 1; - - out = mowgli_mempool_allocate(pool, sz); - mowgli_strlcpy(out, src, sz); - - return out; -} diff --git a/src/libmowgli/mowgli_mempool.h b/src/libmowgli/mowgli_mempool.h deleted file mode 100644 index 14d5911..0000000 --- a/src/libmowgli/mowgli_mempool.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_mempool.h: Memory pooling. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_MEMPOOL_H__ -#define __MOWGLI_MEMPOOL_H__ - -typedef struct mowgli_mempool_t_ mowgli_mempool_t; - -mowgli_mempool_t * mowgli_mempool_create(void); -mowgli_mempool_t * mowgli_mempool_with_custom_destructor(mowgli_destructor_t destructor); - -void * mowgli_mempool_add(mowgli_mempool_t * pool, void * ptr); -void * mowgli_mempool_allocate(mowgli_mempool_t * pool, size_t sz); -void mowgli_mempool_release(mowgli_mempool_t * pool, void * addr); - -void mowgli_mempool_cleanup(mowgli_mempool_t * pool); - -void mowgli_mempool_destroy(mowgli_mempool_t * pool); - -char * mowgli_mempool_strdup(mowgli_mempool_t * pool, char * src); - -#define mowgli_mempool_alloc_object(pool, obj) \ - mowgli_mempool_allocate(pool, sizeof(obj)) - -#endif diff --git a/src/libmowgli/mowgli_spinlock.c b/src/libmowgli/mowgli_spinlock.c deleted file mode 100644 index 47c1166..0000000 --- a/src/libmowgli/mowgli_spinlock.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_spinlock.c: Spinlocks. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -mowgli_spinlock_t *mowgli_spinlock_create(void) -{ - mowgli_spinlock_t *out = mowgli_alloc(sizeof(mowgli_spinlock_t)); - - return out; -} - -void mowgli_spinlock_lock(mowgli_spinlock_t *self, void *r, void *w) -{ - return_if_fail(self != NULL); - - if (r) - mowgli_spinlock_wait(self, MOWGLI_SPINLOCK_READ); - - if (w) - mowgli_spinlock_wait(self, MOWGLI_SPINLOCK_WRITE); - - if (r && (self->read_owner == NULL || self->read_owner == r)) - self->read_owner = r; - - if (w && (self->write_owner == NULL || self->write_owner == w)) - self->write_owner = w; -} - -void mowgli_spinlock_unlock(mowgli_spinlock_t *self, void *r, void *w) -{ - return_if_fail(self != NULL); - - if (r && self->read_owner == r) - self->read_owner = NULL; - - if (w && self->write_owner == w) - self->write_owner = NULL; -} - -void mowgli_spinlock_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param) -{ - return_if_fail(self != NULL) - - if (param == MOWGLI_SPINLOCK_READ) - while (self->read_owner != NULL) - usleep(1000); /* XXX: we'll want a more threadsafe function eventually. */ - - if (param == MOWGLI_SPINLOCK_WRITE) - while (self->write_owner != NULL) - usleep(1000); - - if (param == MOWGLI_SPINLOCK_READWRITE) - while (self->write_owner != NULL || self->read_owner != NULL) - usleep(1000); -} - -void mowgli_spinlock_timed_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param, struct timeval *tv) -{ - struct timeval iter = {0}; - - return_if_fail(self != NULL) - return_if_fail(tv != NULL) - - if (param == MOWGLI_SPINLOCK_READ) - while (self->read_owner != NULL && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) - { - gettimeofday(&iter, NULL); - usleep(1000); /* XXX: we'll want a more threadsafe function eventually. */ - } - - if (param == MOWGLI_SPINLOCK_WRITE) - while (self->write_owner != NULL && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) - { - gettimeofday(&iter, NULL); - usleep(1000); - } - - if (param == MOWGLI_SPINLOCK_READWRITE) - while ((self->write_owner != NULL || self->read_owner != NULL) && iter.tv_sec < tv->tv_sec && iter.tv_usec < tv->tv_usec) - { - gettimeofday(&iter, NULL); - usleep(1000); - } -} diff --git a/src/libmowgli/mowgli_spinlock.h b/src/libmowgli/mowgli_spinlock.h deleted file mode 100644 index 6742e13..0000000 --- a/src/libmowgli/mowgli_spinlock.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_spinlock.h: Spinlocks. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_SPINLOCK_H__ -#define __MOWGLI_SPINLOCK_H__ - -typedef struct { - void *read_owner; /* opaque data representing a spinlock's owner */ - void *write_owner; /* opaque data representing a spinlock's owner */ -} mowgli_spinlock_t; - -typedef enum { - MOWGLI_SPINLOCK_READ, - MOWGLI_SPINLOCK_WRITE, - MOWGLI_SPINLOCK_READWRITE -} mowgli_spinlock_lock_param_t; - -extern mowgli_spinlock_t *mowgli_spinlock_create(void); -extern void mowgli_spinlock_lock(mowgli_spinlock_t *self, void *r, void *w); -extern void mowgli_spinlock_unlock(mowgli_spinlock_t *self, void *r, void *w); -extern void mowgli_spinlock_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param); -extern void mowgli_spinlock_timed_wait(mowgli_spinlock_t *self, mowgli_spinlock_lock_param_t param, struct timeval *tv); - -#endif diff --git a/src/libmowgli/mowgli_stdinc.h b/src/libmowgli/mowgli_stdinc.h deleted file mode 100644 index ae64a22..0000000 --- a/src/libmowgli/mowgli_stdinc.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_stdinc.h: Pulls in the base system includes for libmowgli. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_STDINC_H__ -#define __MOWGLI_STDINC_H__ - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <time.h> -#include <errno.h> -#include <setjmp.h> -#include <sys/stat.h> -#include <ctype.h> - -/* socket stuff */ -#ifndef _WIN32 -# include <netdb.h> -# include <netinet/in.h> -# include <unistd.h> -# include <grp.h> -# include <sys/time.h> -# include <sys/wait.h> -# include <sys/resource.h> -# include <sys/socket.h> -# include <fcntl.h> -# include <arpa/inet.h> -# include <libgen.h> -# include <dirent.h> -#else -# include <windows.h> -# include <winsock.h> -# include <sys/timeb.h> -# include <direct.h> -# include <io.h> -# include <fcntl.h> -#endif - -#include <sys/types.h> - -#ifdef _MSC_VER -# pragma warning (disable: 4996) -#endif - -#ifdef FALSE -# undef FALSE -#endif - -#ifdef TRUE -# undef TRUE -#endif - -typedef enum { FALSE, TRUE } mowgli_boolean_t; - -/* Macros for min/max. */ -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef MAX -# define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - -#if defined(__GNUC__) || defined(_INTEL_COMPILER) -#define MOWGLI_DEPRECATED \ - __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define MOWGLI_DEPRECATED \ - __declspec(deprecated) -#else -#define MOWGLI_DEPRECATED -#endif - -#endif diff --git a/src/libmowgli/mowgli_string.c b/src/libmowgli/mowgli_string.c deleted file mode 100644 index 9c9d5c2..0000000 --- a/src/libmowgli/mowgli_string.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_string.c: Immutable string buffers with cheap manipulation. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * Copyright (c) 2007 Pippijn van Steenhoven <pippijn -at- one09.net> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "mowgli.h" - -mowgli_string_t *mowgli_string_create(void) -{ - mowgli_string_t *self = mowgli_alloc(sizeof(mowgli_string_t)); - - self->size = 64; - self->pos = 0; - self->str = mowgli_alloc(self->size); - - self->append = &mowgli_string_append; - self->append_char = &mowgli_string_append_char; - self->reset = &mowgli_string_reset; - self->destroy = &mowgli_string_destroy; - - return self; -} - -void mowgli_string_reset(mowgli_string_t *self) -{ - return_if_fail(self != NULL); - - self->str[0] = self->pos = 0; -} - -void mowgli_string_destroy(mowgli_string_t *self) -{ - return_if_fail(self != NULL); - - mowgli_free(self->str); - mowgli_free(self); -} - -void mowgli_string_append(mowgli_string_t *self, const char *src, size_t n) -{ - if (self->size - self->pos <= n) - { - char *new; - - self->size = MAX(self->size * 2, self->pos + n + 8); - new = realloc(self->str, self->size); - self->str = new; - } - - memcpy(self->str + self->pos, src, n); - self->pos += n; - self->str[self->pos] = 0; -} - -void mowgli_string_append_char(mowgli_string_t *self, const char c) -{ - if (self->size - self->pos <= 1) - { - char *new; - - self->size = MAX(self->size * 2, self->pos + 9); - new = realloc(self->str, self->size); - self->str = new; - } - - self->str[self->pos++] = c; - self->str[self->pos] = 0; -} - -/* These functions are taken from Linux. */ -size_t mowgli_strlcat(char *dest, const char *src, size_t count) -{ - size_t dsize = strlen(dest); - size_t len = strlen(src); - size_t res = dsize + len; - - dest += dsize; - count -= dsize; - - if (len >= count) - len = count - 1; - - memcpy(dest, src, len); - - dest[len] = 0; - - return res; -} - -size_t mowgli_strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) - { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - - return ret; -} diff --git a/src/libmowgli/mowgli_string.h b/src/libmowgli/mowgli_string.h deleted file mode 100644 index b815451..0000000 --- a/src/libmowgli/mowgli_string.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * libmowgli: A collection of useful routines for programming. - * mowgli_string.h: Immutable string buffers with cheap manipulation. - * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> - * Copyright (c) 2007 Pippijn van Steenhoven <pippijn -at- one09.net> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice is present in all copies. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __MOWGLI_STRING_H__ -#define __MOWGLI_STRING_H__ - -typedef struct mowgli_string_ { - char *str; - size_t pos; - size_t size; - - void (*reset)(struct mowgli_string_ *self); - void (*append)(struct mowgli_string_ *self, const char *src, size_t n); - void (*append_char)(struct mowgli_string_ *self, const char c); - void (*destroy)(struct mowgli_string_ *self); -} mowgli_string_t; - -extern mowgli_string_t *mowgli_string_create(void); -extern void mowgli_string_reset(mowgli_string_t *self); -extern void mowgli_string_destroy(mowgli_string_t *self); -extern void mowgli_string_append(mowgli_string_t *self, const char *src, size_t n); -extern void mowgli_string_append_char(mowgli_string_t *self, const char c); - -extern size_t mowgli_strlcat(char *dest, const char *src, size_t count); -extern size_t mowgli_strlcpy(char *dest, const char *src, size_t count); - -#endif diff --git a/src/libmowgli/object/Makefile b/src/libmowgli/object/Makefile new file mode 100644 index 0000000..1ac3ff3 --- /dev/null +++ b/src/libmowgli/object/Makefile @@ -0,0 +1,21 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_OBJECT} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_OBJECT} + +SRCS = object.c \ + class.c \ + message.c \ + metadata.c + +INCLUDES = object.h \ + class.h \ + message.h \ + metadata.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/object + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/mowgli_object_class.c b/src/libmowgli/object/class.c index 8dc2b83..9bddf79 100644 --- a/src/libmowgli/mowgli_object_class.c +++ b/src/libmowgli/object/class.c @@ -1,7 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_class.c: Object class and type management, - * cast checking. + * class.c: Object class and type management, cast checking. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -48,7 +47,7 @@ void mowgli_object_class_init(mowgli_object_class_t *klass, const char *name, mo mowgli_throw_exception_fatal(mowgli.object_class.duplicate_object_class_exception); /* initialize object_class::name */ - klass->name = strdup(name); + klass->name = mowgli_strdup(name); /* initialize object_class::derivitives */ klass->derivitives.head = NULL; diff --git a/src/libmowgli/mowgli_object_class.h b/src/libmowgli/object/class.h index 03cfd4b..9612aa4 100644 --- a/src/libmowgli/mowgli_object_class.h +++ b/src/libmowgli/object/class.h @@ -1,7 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_class.h: Object class and type management, - * cast checking. + * class.h: Object class and type management, cast checking. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_object_messaging.c b/src/libmowgli/object/message.c index b61a16d..e4328c8 100644 --- a/src/libmowgli/mowgli_object_messaging.c +++ b/src/libmowgli/object/message.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_messaging.c: Object event notification and message passing. + * messaging.c: Object event notification and message passing. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_object_messaging.h b/src/libmowgli/object/message.h index 8fc1f95..4a49d00 100644 --- a/src/libmowgli/mowgli_object_messaging.h +++ b/src/libmowgli/object/message.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_messaging.h: Object event notification and message passing. + * message.h: Object event notification and message passing. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_object_metadata.c b/src/libmowgli/object/metadata.c index 9cfece5..742e0dc 100644 --- a/src/libmowgli/mowgli_object_metadata.c +++ b/src/libmowgli/object/metadata.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_metadata.c: Object metadata. + * metadata.c: Object metadata. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -49,7 +49,7 @@ void mowgli_object_metadata_associate(mowgli_object_t *self, const char *key, vo } e = mowgli_alloc(sizeof(mowgli_object_metadata_entry_t)); - e->name = strdup(key); + e->name = mowgli_strdup(key); e->data = value; mowgli_node_add(e, mowgli_node_create(), &self->metadata); diff --git a/src/libmowgli/mowgli_object_metadata.h b/src/libmowgli/object/metadata.h index 5f93b8e..0cdda69 100644 --- a/src/libmowgli/mowgli_object_metadata.h +++ b/src/libmowgli/object/metadata.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object_metadata.h: Object metadata. + * metadata.h: Object metadata. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/mowgli_object.c b/src/libmowgli/object/object.c index 731f1c5..7b24ea7 100644 --- a/src/libmowgli/mowgli_object.c +++ b/src/libmowgli/object/object.c @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object.c: Object management. + * object.c: Object management. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * @@ -45,7 +45,7 @@ void mowgli_object_init(mowgli_object_t *obj, const char *name, mowgli_object_cl return_if_fail(obj != NULL); if (name != NULL) - obj->name = strdup(name); + obj->name = mowgli_strdup(name); if (klass != NULL) obj->klass = klass; diff --git a/src/libmowgli/mowgli_object.h b/src/libmowgli/object/object.h index 5bcee2a..0f13ce1 100644 --- a/src/libmowgli/mowgli_object.h +++ b/src/libmowgli/object/object.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_object.h: Object management. + * object.h: Object management. * * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> * diff --git a/src/libmowgli/platform/Makefile b/src/libmowgli/platform/Makefile new file mode 100644 index 0000000..6b6d7b9 --- /dev/null +++ b/src/libmowgli/platform/Makefile @@ -0,0 +1,9 @@ +SUBDIRS = win32 + +INCLUDES = constructor.h machine.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/platform + +include ../../../extra.mk diff --git a/src/libmowgli/platform/autoconf.h.in b/src/libmowgli/platform/autoconf.h.in new file mode 100644 index 0000000..fb77f69 --- /dev/null +++ b/src/libmowgli/platform/autoconf.h.in @@ -0,0 +1,105 @@ +/* src/libmowgli/platform/autoconf.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `dispatch_block' function. */ +#undef HAVE_DISPATCH_BLOCK + +/* Define to 1 if you have the `fcntl' function. */ +#undef HAVE_FCNTL + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if OpenSSL is available */ +#undef HAVE_OPENSSL + +/* Define to 1 if you have the <poll.h> header file. */ +#undef HAVE_POLL_H + +/* Define to 1 if you have the `port_create' function. */ +#undef HAVE_PORT_CREATE + +/* Define to 1 if you have the `pstat' function. */ +#undef HAVE_PSTAT + +/* Define to 1 if the PS_STRINGS struct exists on your platform (likely no). + */ +#undef HAVE_PS_STRINGS + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/epoll.h> header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define to 1 if you have the <sys/prctl.h> header file. */ +#undef HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the <sys/pstat.h> header file. */ +#undef HAVE_SYS_PSTAT_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the <winsock2.h> header file. */ +#undef HAVE_WINSOCK2_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/src/libmowgli/mowgli_logger.h b/src/libmowgli/platform/constructor.h index 730383a..8446f44 100644 --- a/src/libmowgli/mowgli_logger.h +++ b/src/libmowgli/platform/constructor.h @@ -1,8 +1,8 @@ /* - * libmowgli: A collection of useful routines for programming. - * mowgli_logger.h: Event and debugging message logging. + * constructor.h + * Code for setting up automatic initializer functions portably. * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,25 +21,34 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MOWGLI_LOGGER_H__ -#define __MOWGLI_LOGGER_H__ +#ifndef __MOWGLI_PLATFORM_CONSTRUCTOR_H__ +#define __MOWGLI_PLATFORM_CONSTRUCTOR_H__ -typedef void (*mowgli_log_cb_t)(const char *); +#ifdef _MSC_VER + +/* + * Automatic constructors are not yet officially supported in MSVC, however, + * there is a similar feature where functions in the ".CRT$XCU" section are + * evaluated prior to DllMain(), main() and friends. + * + * See http://blogs.msdn.com/b/vcblog/archive/2006/10/20/crt-initialization.aspx + * for more information. + */ +#define MOWGLI_BOOTSTRAP_FUNC(func) \ + static void __cdecl func(void); \ + __declspec(allocate(".CRT$XCU")) void (__cdecl *func##_)(void) = func; \ + static void __cdecl func(void) + +#elif defined(__GNUC__) || defined(__SUNPRO_C) + +#define MOWGLI_BOOTSTRAP_FUNC(func) \ + static void func(void) __attribute__((constructor)); \ + static void func(void) -#ifdef __GNUC__ -# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__) -#elif defined _MSC_VER -# if _MSC_VER <= 1200 - static __inline void mowgli_log(char *fmt, ...) { /* TODO/UNSUPPORTED */ } -# else -# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) -# endif #else -# define mowgli_log(...) mowgli_log_real(__FILE__, __LINE__, __func__, __VA_ARGS__) -#endif -extern void mowgli_log_real(const char *file, int line, const char *func, const char *buf, ...); +#error MOWGLI_BOOTSTRAP_FUNC not implemented for your platform :( -extern void mowgli_log_set_cb(mowgli_log_cb_t callback); +#endif #endif diff --git a/src/libmowgli/platform/machine.h b/src/libmowgli/platform/machine.h new file mode 100644 index 0000000..b2a2e50 --- /dev/null +++ b/src/libmowgli/platform/machine.h @@ -0,0 +1,334 @@ +/* + * libmowgli: A collection of useful routines for programming. + * machine.h: Defines to discover what machine we're on easily + * + * Copyright (c) 2012 Patrick McFarland <pmcfarland@adterrasperaspera.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* Machine environment specific macros, mostly sourced from this URL: + * http://sourceforge.net/apps/mediawiki/predef/ + * + * Please note: Just because a compiler, CPU, or OS is listed in this file, + * that doesn't mean that it is supported by libmowgli. libmowgli requires + * a 32-bit or higher CPU and an OS that supports a supported mutex and + * thread scheme (if you intend on having functional multithreaded + * operation). + */ + +#ifndef __MOWGLI_MACHINE_H__ +#define __MOWGLI_MACHINE_H__ + +#if defined __clang__ +#define MOWGLI_COMPILER_CLANG +#define MOWGLI_COMPILER clang +#elif defined __INTEL_COMPILER || defined __ICC || defined __ICL +#define MOWGLI_COMPILER_ICC +#define MOWGLI_COMPILER icc +#elif defined __CC_ARM +#define MOWGLI_COMPILER_ARM +#define MOWGLI_COMPILER arm +#elif defined __xlc__ || defined __xlC__ +#define MOWGLI_COMPILER_IBM +#define MOWGLI_COMPILER ibm +#elif defined __SUNPRO_C || defined __SUNPRO_CC +#define MOWGLI_COMPILER_SUN +#define MOWGLI_COMPILER sun +#elif defined __GNUC__ +#define MOWGLI_COMPILER_GCC +#define MOWGLI_COMPILER gcc +#elif defined _MSC_VER +#define MOWGLI_COMPILER_MSVC +#define MOWGLI_COMPILER msvc +#else +#define MOWGLI_COMPILER_UNKNOWN +#define MOWGLI_COMPILER unknown +#endif + +#if defined __GNUC__ +#define MOWGLI_COMPILER_GCC_COMPAT +#endif + +#if defined __amd64__ || defined __amd64 || defined __x86_64__ || defined __x86_64 || defined _M_X64 || defined _M_AMD64 +#define MOWGLI_CPU_X86_64 +#define MOWGLI_CPU x86_64 +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#elif defined __i386__ || defined __i386 || defined __IA32__ || defined _M_IX86 || defined __X86__ || defined _X86__ || defined __I86__ +#define MOWGLI_CPU_X86 +#define MOWGLI_CPU x86 +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#elif defined __arm__ || defined __TARGET_ARCH_ARM || defined _ARM +#if defined __thumb__ || defined __TARGET_ARCH_THUMB +#define MOWGLI_CPU_ARM_THUMB +#endif +#define MOWGLI_CPU_ARM +#define MOWGLI_CPU arm +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +// ARM can be either endian +#elif defined __hppa__ || defined __HPPA__ || defined __hppa +#if defined _PA_RISC2_0 || defined __HPPA20__ || defined __RISC2_0__ +#define MOWGLI_CPU_HPPA20 +#define MOWGLI_CPU hppa20 +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#else +#define MOWGLI_CPU_HPPA10 +#define MOWGLI_CPU hppa10 +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#endif +#define MOWGLI_CPU_ENDIAN_BIG +#define MOWGLI_CPU_ENDIAN big +#elif defined __ia64__ || defined __IA64__ || defined _M_IA64 || defined __ia64 || defined __itanium__ +#define MOWGLI_CPU_ITANIUM +#define MOWGLI_CPU itanium +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +// Itanium can be either endian +#elif defined __mips__ || defined mips || defined __mips || defined __MIPS__ +#if defined __mips64 || defined __mips64__ +#define MOWGLI_CPU_MIPS64 +#define MOWGLI_CPU mips64 +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#else +#define MOWGLI_CPU_MIPS +#define MOWGLI_CPU mips +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#endif +// MIPS can be either endian +#elif defined __powerpc || defined __powerpc__ || defined __POWERPC__ || defined __ppc__ || defined _M_PPC +#if defined __ppc64__ || defined __PPC64__ +#define MOWGLI_CPU_POWERPC64 +#define MOWGLI_CPU powerpc64 +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#else +#define MOWGLI_CPU powerpc +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#endif +#define MOWGLI_CPU_POWERPC +// PowerPC can be either endian +#elif defined __sparc__ || defined __sparc +#if defined __sparcv9 || defined __sparc64 || defined __sparc64__ +#define MOWGLI_CPU_SPARC64 +#define MOWGLI_CPU sparc64 +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#else +#define MOWGLI_CPU_SPARC +#define MOWGLI_CPU sparc +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#endif +#define MOWGLI_CPU_ENDIAN_BIG +#define MOWGLI_CPU_ENDIAN big +#elif defined __alpha || defined __alpha__ || defined _M_ALPHA +#define MOWGLI_CPU_ALPHA +#define MOWGLI_CPU alpha +#define MOWGLI_CPU_BITS_64 +#define MOWGLI_CPU_BITS 64 +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#elif defined __avr32__ || defined __AVR32__ +#define MOWGLI_CPU_AVR32 +#define MOWGLI_CPU avr +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#elif defined __sh__ || defined __SH__ +#define MOWGLI_CPU_SuperH +#define MOWGLI_CPU superh +#define MOWGLI_CPU_BITS_32 +#define MOWGLI_CPU_BITS 32 +// SyoerH can be either endian +#endif + +#ifndef MOWGLI_CPU +#define MOWGLI_CPU_UNKNOWN +#define MOWGLI_CPU unknown +#endif + +#ifndef MOWGLI_CPU_BITS +#if defined _LP64 || defined __LP64 +#define MOWGLI_CPU_BITS 64 +#define MOWGLI_CPU_BITS_64 +#elif +#define MOWGLI_CPU_BITS 32 +#define MOWGLI_CPU_BITS_32 +#endif +#endif + +#if defined __linux || defined __linux__ +#define MOWGLI_OS_LINUX +#define MOWGLI_OS linux +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#elif defined __APPLE__ +#define MOWGLI_OS_OSX +#define MOWGLI_OS osx +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_BSD_TYPE + +#ifdef MOWGLI_CPU_POWERPC +#define MOWGLI_CPU_ENDIAN_BIG +#define MOWGLI_CPU_ENDIAN big +#endif +#elif defined __WINDOWS__ || defined _WIN32 || defined __WIN32__ || defined __TOS_WIN__ +#if defined _WIN64 +#define MOWGLI_OS_WIN64 +#define MOWGLI_OS win64 +#else +#define MOWGLI_OS_WIN32 +#define MOWGLI_OS win32 +#endif +#define MOWGLI_OS_WIN +#define MOWGLI_OS_THREADS_WIN +#define MOWGLI_OS_THREADS win +#define MOWGLI_OS_MUTEX_WIN +#define MOWGLI_OS_MUTEX win + +#if defined __CYGWIN__ +#define MOWGLI_OS_WIN_CYGWIN +#elif defined __MINGW32__ +#define MOWGLI_OS_WIN_MINGW +#endif + +#if defined MOWGLI_CPU_POWERPC || defined MOWGLI_CPU_MIPS || defined MOWGLI_CPU_ITANIUM +#define MOWGLI_ENDIAN_CPU_LITTLE +#endif +#elif defined __NetBSD__ || defined __OpenBSD__ || defined __FreeBSD__ || defined __bsdi__ || defined __DragonFly__ || defined BSD || defined _SYSTYPE_BSD +#define MOWGLI_OS_BSD +#define MOWGLI_OS bsd +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_BSD_TYPE +#elif defined __GNU__ +#define MOWGLI_OS_HURD +#define MOWGLI_OS hurd +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#elif defined sco || defined __sco +#define MOWGLI_OS_SCO +#define MOWGLI_OS sco +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_UNIX_TYPE +#elif defined sun || defined __sun +#define MOWGLI_OS_SOLARIS +#define MOWGLI_OS solaris +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_UNIX_TYPE +#if defined MOWGLI_CPU_POWERPC +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#endif +#elif defined _hpux || defined hpux || defined __hpux +#define MOWGLI_OS_HPUX +#define MOWGLI_OS hpux +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_UNIX_TYPE +#if defined MOWGLI_CPU_ITANIUM +#define MOWGLI_CPU_ENDIAN_BIG +#define MOWGLI_CPU_ENDIAN big +#endif +#elif defined __QNX__ || defined __QNXNTO__ +#define MOWGLI_OS_QNX +#define MOWGLI_OS qnx +#define MOWGLI_OS_THREADS_QNX +#define MOWGLI_OS_THREADS qnx +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#elif defined __vms || defined __VMS +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#if defined MOWGLI_CPU_ITANIUM +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#endif +#endif + +#ifndef MOWGLI_OS +#if defined __unix__ || __unix || unix +#define MOWGLI_OS_UNIX +#define MOWGLI_OS unix +#define MOWGLI_OS_THREADS_POSIX +#define MOWGLI_OS_THREADS posix +#define MOWGLI_OS_MUTEX_POSIX +#define MOWGLI_OS_MUTEX posix +#define MOWGLI_OS_UNIX_TYPE +#endif +#define MOWGLI_OS_UNKNOWN +#define MOWGLI_OS unknown +#warning OS unsupported/unknown +#endif + +#ifndef MOWGLI_OS_THREADS +#define MOWGLI_OS_THREADS_NULL +#define MOWGLI_OS_THREADS null +#endif + +#ifndef MOWGLI_OS_MUTEX +#define MOWGLI_OS_MUTEX_NULL +#define MOWGLI_OS_MUTEX null +#endif + +#ifndef MOWGLI_CPU_ENDIAN +#if defined __BIG_ENDIAN__ || defined __ARMEB__ || defined __THUMBEB__ || defined _MIPSEB || defined __MIPSEB || defined __MIPSEB__ || __BYTE_ORDER == __BIG_ENDIAN +#define MOWGLI_CPU_ENDIAN_BIG +#define MOWGLI_CPU_ENDIAN big +#elif defined __LITTLE_ENDIAN__ || defined __ARMEL__ || defined __THUMBEL__ || defined _MIPSEL || defined __MIPSEL || defined __MIPSEL__ || __BYTE_ORDER == __LITTLE_ENDIAN +#define MOWGLI_CPU_ENDIAN_LITTLE +#define MOWGLI_CPU_ENDIAN little +#else +#warning CPU endianness unknown, some functions of libmowgli will not work +#endif +#endif + +#endif diff --git a/src/libmowgli/platform/win32/Makefile b/src/libmowgli/platform/win32/Makefile new file mode 100644 index 0000000..653bf2d --- /dev/null +++ b/src/libmowgli/platform/win32/Makefile @@ -0,0 +1,15 @@ +include ../../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_PLATFORM_WIN32} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_PLATFORM_WIN32} + +SRCS = fork.c gettimeofday.c inet.c pipe.c socketpair.c setenv.c + +INCLUDES = win32_stdinc.h + +include ../../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/platform/win32 + +CPPFLAGS += -I. -I.. -I../.. -I../../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/platform/win32/fork.c b/src/libmowgli/platform/win32/fork.c new file mode 100644 index 0000000..c644122 --- /dev/null +++ b/src/libmowgli/platform/win32/fork.c @@ -0,0 +1,166 @@ +/* + * libmowgli: A collection of useful routines for programming. + * fork.c: Fastest possible NT fork() implementation + * + * Copyright (c) 2012 TortoiseLabs, LLC. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * References: + * - undocumented.ntinternals.net + * - http://www.cs.miami.edu/~burt/journal/NT/processinit.html + */ + +#include "mowgli.h" + +#ifdef NOTYET + +#ifdef _WIN32 + +#ifndef _WIN32_WINNT + +int fork(void) +{ +#warning fork is not possible on your platform in any sane way, sorry :( + return -ENOSYS; +} + +#else + +extern NTSTATUS NTAPI CsrCallClientServer(void *message, void *userdata, uint32_t opcode, uint32_t size); + +/* + * Definition of a message sent to an NT port on the CSRSS server. + * + * Not sure what dummy1/dummy2 do, but they're junk as far as I can see. + */ +struct csrss_message { + uint32_t dummy1; + uint32_t opcode; + uint32_t status; + uint32_t dummy2; +}; + +static inline void +inherit_handles(void) +{ + uint32_t n = 0x1000; + uint32_t *p = mowgli_alloc_array(sizeof(uint32_t), n); + uint32_t pid, i; + SYSTEM_HANDLE_INFORMATION *info; + + while (ZwQuerySystemInformation(SystemHandleInformation, p, n * sizeof(*p), 0) == STATUS_INFO_LENGTH_MISMATCH) + { + n *= 2; + + mowgli_free(p); + p = mowgli_alloc_array(sizeof(uint32_t), n); + } + + info = (SYSTEM_HANDLE_INFORMATION *) (p + 1); + pid = GetCurrentProcessId(); + + for (i = 0; i < *p; i++) + { + if (info[i].ProcessId == pid) + SetHandleInformation((HANDLE) h[i].Handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + } + + mowgli_free(p); +} + +static inline void +request_csrss_session(HANDLE proc_handle, HANDLE thread_handle, uint32_t pid, uint32_t tid) +{ + struct { + PORT_MESSAGE port_message; + struct csrss_message csrss_message; + PROCESS_INFORMATION process_information; + CLIENT_ID debugger; + uint32_t flags; + uint32_t vdminfo[2]; + } csrmsg = {{0}, {0}, {proc_handle, thread_handle, pid, tid}, {0}, 0, {0}}; + + CsrCallClientServer(&csrmsg, NULL, 0x10000, sizeof csrmsg); +} + +int child(void) +{ + typedef BOOL (*CsrpConnectToServer)(PWSTR); + + CsrpConnectToServer (0x77F8F65D) (L"\\Windows"); + __asm__("mov eax, 0; mov esp, ebp; pop ebp; ret"); +} + +int fork(void) +{ + HANDLE proc_handle, thread_handle; + OBJECT_ATTRIBUTES oa = { sizeof(oa) }; + CONTEXT context = { CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT }; + MEMORY_BASIC_INFORMATION mbi; + THREAD_BASIC_INFORMATION tbi; + PNT_TIB tib; + USER_STACK stack; + CLIENT_ID cid; + + /* ensure the child has the same handles and ports */ + inherit_handles(); + + /* create the actual LWP using ZwCreateProcess() */ + ZwCreateProcess(&proc_handle, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), TRUE, 0, 0, 0); + + /* now set up a thread for that process using a context, cloning the current thread ... */ + ZwGetContextThread(NtCurrentThread(), &context); + context.Eip = (unsigned long) child; + + /* set up a stack for the thread now that the child sentinel is set up ... */ + ZwQueryVirtualMemory(NtCurrentProcess(), (void *) context.Esp, MemoryBasicInformation, + &mbi, sizeof mbi, 0); + + stack = (USER_STACK){0, 0, ((char *) mbi.BaseAddress) + mbi.RegionSize, + mbi.BaseAddress, mbi.AllocationBase}; + + /* now spawn the thread! */ + ZwCreateThread(&thread_handle, THREAD_ALL_ACCESS, &oa, proc_handle, &cid, &context, &stack, TRUE); + + /* thread is spawned, but frozen for inspection -- fix up memory protection before unfreezing */ + ZwQueryInformationThread(NtCurrentThread(), ThreadBasicInformation, &tbi, sizeof tbi, 0); + tib = tbi.TebBaseAddress; + + ZwQueryInformationThread(thread_handle, ThreadBasicInformation, &tbi, sizeof tbi, 0); + ZwWriteVirtualMemory(process_handle, tbi.TebBaseAddress, &tib->ExceptionList, sizeof(tib->ExceptionList), 0); + + /* ready to go, now request a CSRSS session */ + request_csrss_session(process_handle, thread_handle, (uint32_t) cid.UniqueProcess, (uint32_t) cid.UniqueThread); + + /* CSRSS session set up or we segfaulted by now, so unfreeze the child... */ + ZwResumeThread(thread_handle, 0); + + /* release handle refcount now that process is freestanding */ + ZwClose(thread_handle); + ZwClose(process_handle); + + return (int) cid.UniqueProcess; +} + +#endif + +#endif + +#endif diff --git a/src/libmowgli/win32_support.c b/src/libmowgli/platform/win32/gettimeofday.c index da6344f..1e96797 100644 --- a/src/libmowgli/win32_support.c +++ b/src/libmowgli/platform/win32/gettimeofday.c @@ -29,10 +29,11 @@ # define EPOCH_TIME_IN_MICROSECS 11644473600000000ULL #endif +#ifdef _WIN32 int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; - ULARGE_INTEGER tmpres = { 0 }; + ULARGE_INTEGER tmpres; static mowgli_boolean_t tz_init_done = FALSE; if (tv != NULL) @@ -62,3 +63,4 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) return 0; } +#endif diff --git a/src/libmowgli/platform/win32/inet.c b/src/libmowgli/platform/win32/inet.c new file mode 100644 index 0000000..051ae7f --- /dev/null +++ b/src/libmowgli/platform/win32/inet.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef _WIN32 + +int inet_pton(int af, const char *src, void *dst) +{ + struct sockaddr_storage ss; + int size = sizeof(struct sockaddr_storage); + char src_copy[INET6_ADDRSTRLEN + 1]; + + mowgli_strlcpy(src_copy, src, sizeof src_copy); + + if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *) &ss, &size) != SOCKET_ERROR) + { + switch (af) + { + case AF_INET: + *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; + return 1; + + case AF_INET6: + *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; + return 1; + + default: + return 0; + } + } + + return -1; +} + +const char *inet_ntop(int af, const void *addr, char *host, size_t hostlen) +{ + struct sockaddr_storage ss; + int size = sizeof(struct sockaddr_storage); + + ss.ss_family = af; + + switch (af) + { + case AF_INET: + memcpy(&(((struct sockaddr_in *) &ss)->sin_addr), (struct in_addr *) addr, sizeof (struct in_addr)); + break; + + case AF_INET6: + memcpy(&(((struct sockaddr_in6 *) &ss)->sin6_addr), (struct in6_addr *) addr, sizeof (struct in6_addr)); + break; + + default: + return NULL; + } + + if (WSAAddressToString((struct sockaddr *) &ss, size, 0, host, (LPDWORD) &hostlen) != SOCKET_ERROR) + return host; + + return NULL; +} + +#endif diff --git a/src/libmowgli/mowgli_init.h b/src/libmowgli/platform/win32/pipe.c index 3ebc7e3..5da3dd2 100644 --- a/src/libmowgli/mowgli_init.h +++ b/src/libmowgli/platform/win32/pipe.c @@ -1,8 +1,8 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_init.c: Initialization of libmowgli. + * pipe.c: UNIX pipe emulation * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2012 TortoiseLabs, LLC. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,9 +21,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MOWGLI_INIT_H__ -#define __MOWGLI_INIT_H__ - -extern void mowgli_init(void); +#include "mowgli.h" +#ifdef _WIN32 +int pipe(int pipefd[2]) +{ + return socketpair(AF_INET, SOCK_STREAM, 0, pipefd); +} #endif diff --git a/src/libmowgli/mowgli_allocator.h b/src/libmowgli/platform/win32/setenv.c index 1e2b703..f80a574 100644 --- a/src/libmowgli/mowgli_allocator.h +++ b/src/libmowgli/platform/win32/setenv.c @@ -1,8 +1,8 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_allocator.h: Builtin allocation policies (mmap/malloc). + * setenv.c: setenv() wrapper around SetEnvironmentVariable(). * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2012 TortoiseLabs, LLC. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,11 +21,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __MOWGLI_ALLOCATOR_H__ -#define __MOWGLI_ALLOCATOR_H__ - -void mowgli_allocator_init(void) MOWGLI_DEPRECATED; -extern mowgli_allocation_policy_t *mowgli_allocator_malloc MOWGLI_DEPRECATED; +#include "mowgli.h" +#ifdef _WIN32 +int setenv(const char *name, const char *value, int overwrite) +{ + return !SetEnvironmentVariable(name, value); +} #endif - diff --git a/src/libmowgli/platform/win32/socketpair.c b/src/libmowgli/platform/win32/socketpair.c new file mode 100644 index 0000000..6ede51e --- /dev/null +++ b/src/libmowgli/platform/win32/socketpair.c @@ -0,0 +1,109 @@ +/* socketpair.c + * Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org> + * This code is Free Software. It may be copied freely, in original or + * modified form, subject only to the restrictions that (1) the author is + * relieved from all responsibilities for any use for any purpose, and (2) + * this copyright notice must be retained, unchanged, in its entirety. If + * for any reason the author might be held responsible for any consequences + * of copying or use, license is withheld. + */ + +/* Changes: + * 2010-03-31: + * set addr to 127.0.0.1 because win32 getsockname does not always set it. + * 2010-02-25: + * set SO_REUSEADDR option to avoid leaking some windows resource. + * Windows System Error 10049, "Event ID 4226 TCP/IP has reached + * the security limit imposed on the number of concurrent TCP connect + * attempts." Bleah. + * 2007-04-25: + * preserve value of WSAGetLastError() on all error returns. + * 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>) + * s/EINVAL/WSAEINVAL/ fix trivial compile failure + * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout + * of a child process. + * add argument make_overlapped + */ + +#include "mowgli.h" + +#ifdef _WIN32 + +/* dumb_socketpair: + * If make_overlapped is nonzero, both sockets created will be usable for + * "overlapped" operations via WSASend etc. If make_overlapped is zero, + * socks[0] (only) will be usable with regular ReadFile etc., and thus + * suitable for use as stdin or stdout of a child process. Note that the + * sockets must be closed with closesocket() regardless. + */ + +int socketpair(int domain, int type, int protocol, int socks[2]) +{ + union { + struct sockaddr_in inaddr; + struct sockaddr addr; + } a; + SOCKET listener; + int e; + socklen_t addrlen = sizeof(a.inaddr); + int make_overlapped = 0; + DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0); + int reuse = 1; + + if (socks == NULL) { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listener == INVALID_SOCKET) + return SOCKET_ERROR; + + memset(&a, 0, sizeof(a)); + a.inaddr.sin_family = AF_INET; + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_port = 0; + + socks[0] = socks[1] = INVALID_SOCKET; + do { + if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, + (char*) &reuse, (socklen_t) sizeof(reuse)) == -1) + break; + if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + memset(&a, 0, sizeof(a)); + if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR) + break; + // win32 getsockname may only set the port number, p=0.0005. + // ( http://msdn.microsoft.com/library/ms738543.aspx ): + a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + a.inaddr.sin_family = AF_INET; + + if (listen(listener, 1) == SOCKET_ERROR) + break; + + socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags); + if (socks[0] == (int) INVALID_SOCKET) + break; + if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR) + break; + + socks[1] = accept(listener, NULL, NULL); + if (socks[1] == (int) INVALID_SOCKET) + break; + + closesocket(listener); + return 0; + + } while (0); + + e = WSAGetLastError(); + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + WSASetLastError(e); + return SOCKET_ERROR; +} + +#endif diff --git a/src/libmowgli/win32_support.h b/src/libmowgli/platform/win32/win32_stdinc.h index c87c643..1360a4a 100644 --- a/src/libmowgli/win32_support.h +++ b/src/libmowgli/platform/win32/win32_stdinc.h @@ -1,6 +1,6 @@ /* * libmowgli: A collection of useful routines for programming. - * win32_support.h: Support functions and values for Win32 platform. + * win32_stdinc.h: Support functions and values for Win32 platform. * * Copyright (c) 2009 SystemInPlace, Inc. * @@ -26,14 +26,16 @@ #ifdef _WIN32 -#include <winsock.h> // just for struct timeval declaration +#include <winsock2.h> +#include <ws2tcpip.h> #include <time.h> #define strcasecmp _stricmp #define strdup _strdup #define usleep(_usecs) Sleep((_usecs)/1000L) -#define snprintf _snprintf -#define vsnprintf _vsnprintf +#ifdef _MSC_VER +# define snprintf _snprintf +#endif struct timezone { int tz_minuteswest; @@ -41,6 +43,19 @@ struct timezone { }; extern int gettimeofday(struct timeval *tv, struct timezone *tz); +extern int setenv(const char *name, const char *value, int overwrite); +extern int pipe(int pipefd[2]); +extern int socketpair(int domain, int type, int protocol, int pipefd[2]); +extern int fork(void); +extern int inet_pton(int af, const char *src, void *dst); +extern const char *inet_ntop(int af, const void *addr, char *host, size_t hostlen); + +/* MSYS autoconf is fucko. */ +#ifndef HAVE_WINSOCK2_H +#define HAVE_WINSOCK2_H +#endif + +#define HAVE_SELECT #endif diff --git a/src/libmowgli/thread/Makefile b/src/libmowgli/thread/Makefile new file mode 100644 index 0000000..c0e51e4 --- /dev/null +++ b/src/libmowgli/thread/Makefile @@ -0,0 +1,18 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_THREAD} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_THREAD} + +SRCS = mutex.c \ + null_mutexops.c \ + posix_mutexops.c \ + win32_mutexops.c + +INCLUDES = thread.h mutex.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/thread + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/thread/mutex.c b/src/libmowgli/thread/mutex.c new file mode 100644 index 0000000..1d5d480 --- /dev/null +++ b/src/libmowgli/thread/mutex.c @@ -0,0 +1,134 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mutex.c: Cross-platform mutexes. + * + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#if defined(_WIN32) +extern const mowgli_mutex_ops_t _mowgli_win32_mutex_ops; +#elif defined(_sun) || defined(_sco) +extern const mowgli_mutex_ops_t _mowgli_sun_mutex_ops; +#else +extern const mowgli_mutex_ops_t _mowgli_posix_mutex_ops; +#endif + +extern const mowgli_mutex_ops_t _mowgli_null_mutex_ops; + +static const mowgli_mutex_ops_t *_mowgli_mutex_ops = NULL; + +static inline const mowgli_mutex_ops_t *get_mutex_platform(void) +{ + /* allow for threading policy to set custom mutex ops */ + if (_mowgli_mutex_ops != NULL) + return _mowgli_mutex_ops; + +#if defined(_WIN32) + return &_mowgli_win32_mutex_ops; +#endif + +#if defined(_sun) || defined(_sco) + return &_mowgli_sun_mutex_ops; +#endif + +#if !defined(MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES) + return &_mowgli_posix_mutex_ops; +#endif + + return &_mowgli_null_mutex_ops; +} + +mowgli_mutex_t *mowgli_mutex_create(void) +{ + mowgli_mutex_t *mutex = mowgli_alloc(sizeof(mowgli_mutex_t)); + + return_val_if_fail(mutex != NULL, NULL); + + if (mowgli_mutex_init(mutex)) + return mutex; + else + { + mowgli_free(mutex); + return NULL; + } +} + +int mowgli_mutex_init(mowgli_mutex_t *mutex) +{ + return_val_if_fail(mutex != NULL, -1); + + mutex->ops = get_mutex_platform(); + + return mutex->ops->mutex_create(mutex); +} + +int mowgli_mutex_lock(mowgli_mutex_t *mutex) +{ + return_val_if_fail(mutex != NULL, -1); + return_val_if_fail(mutex->ops != NULL, -1); + + return mutex->ops->mutex_lock(mutex); +} + +int mowgli_mutex_trylock(mowgli_mutex_t *mutex) +{ + return_val_if_fail(mutex != NULL, -1); + return_val_if_fail(mutex->ops != NULL, -1); + + return mutex->ops->mutex_trylock(mutex); +} + +int mowgli_mutex_unlock(mowgli_mutex_t *mutex) +{ + return_val_if_fail(mutex != NULL, -1); + return_val_if_fail(mutex->ops != NULL, -1); + + return mutex->ops->mutex_unlock(mutex); +} + +int mowgli_mutex_uninit(mowgli_mutex_t *mutex) +{ + return_val_if_fail(mutex != NULL, -1); + return_val_if_fail(mutex->ops != NULL, -1); + + return mutex->ops->mutex_destroy(mutex); +} + +void mowgli_mutex_destroy(mowgli_mutex_t *mutex) +{ + return_if_fail(mutex != NULL); + + mowgli_mutex_uninit(mutex); + mowgli_free(mutex); +} + +void mowgli_mutex_set_policy(mowgli_thread_policy_t policy) +{ + switch (policy) + { + case MOWGLI_THREAD_POLICY_DISABLED: + _mowgli_mutex_ops = &_mowgli_null_mutex_ops; + break; + case MOWGLI_THREAD_POLICY_DEFAULT: + default: + _mowgli_mutex_ops = NULL; + } +} diff --git a/src/libmowgli/thread/mutex.h b/src/libmowgli/thread/mutex.h new file mode 100644 index 0000000..f08013d --- /dev/null +++ b/src/libmowgli/thread/mutex.h @@ -0,0 +1,79 @@ +/* + * libmowgli: A collection of useful routines for programming. + * mutex.h: Cross-platform mutexes. + * + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_MUTEX_H__ +#define __MOWGLI_MUTEX_H__ + +#ifdef MOWGLI_OS_UNIX_TYPE +# include <thread.h> +# include <synch.h> +# define MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES +# define MOWGLI_NATIVE_MUTEX_DECL(name) mutex_t (name) +#elif defined MOWGLI_OS_WIN +# define MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES +# define MOWGLI_NATIVE_MUTEX_DECL(name) HANDLE (name) +#else +# include <pthread.h> +#endif + +typedef struct mowgli_mutex_ mowgli_mutex_t; + +typedef struct { + int (*mutex_create)(mowgli_mutex_t *mutex); + int (*mutex_lock)(mowgli_mutex_t *mutex); + int (*mutex_trylock)(mowgli_mutex_t *mutex); + int (*mutex_unlock)(mowgli_mutex_t *mutex); + int (*mutex_destroy)(mowgli_mutex_t *mutex); +} mowgli_mutex_ops_t; + +struct mowgli_mutex_ { +#ifdef MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES + MOWGLI_NATIVE_MUTEX_DECL(mutex); +#else + pthread_mutex_t mutex; +#endif + const mowgli_mutex_ops_t *ops; +}; + +#ifdef MOWGLI_NATIVE_MUTEX_DECL +# undef MOWGLI_NATIVE_MUTEX_DECL +#endif + +mowgli_mutex_t *mowgli_mutex_create(void); +int mowgli_mutex_init(mowgli_mutex_t* mutex); +int mowgli_mutex_lock(mowgli_mutex_t *mutex); +int mowgli_mutex_trylock(mowgli_mutex_t *mutex); +int mowgli_mutex_unlock(mowgli_mutex_t *mutex); +int mowgli_mutex_uninit(mowgli_mutex_t *mutex); +void mowgli_mutex_destroy(mowgli_mutex_t *mutex); + +void mowgli_mutex_set_policy(mowgli_thread_policy_t policy); + +/* simple dispatch function to set the ops up for the various subsystems. */ +static inline void mowgli_thread_set_policy(mowgli_thread_policy_t policy) +{ + mowgli_mutex_set_policy(policy); +} + +#endif + diff --git a/src/libmowgli/mowgli_allocator.c b/src/libmowgli/thread/null_mutexops.c index 8c4bd69..2750add 100644 --- a/src/libmowgli/mowgli_allocator.c +++ b/src/libmowgli/thread/null_mutexops.c @@ -1,8 +1,8 @@ /* * libmowgli: A collection of useful routines for programming. - * mowgli_allocator.h: Builtin allocation policies (mmap/malloc). + * null_mutexops.c: null mutex operations * - * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,24 +23,35 @@ #include "mowgli.h" -mowgli_allocation_policy_t *mowgli_allocator_malloc = NULL; +static int mowgli_null_mutex_create(mowgli_mutex_t *mutex) +{ + return 0; +} + +static int mowgli_null_mutex_lock(mowgli_mutex_t *mutex) +{ + return 0; +} -static void * -mowgli_allocator_func_malloc(int size) +static int mowgli_null_mutex_trylock(mowgli_mutex_t *mutex) { - return calloc(size, 1); + return 0; } -static void -mowgli_allocator_func_free(void *ptr) +static int mowgli_null_mutex_unlock(mowgli_mutex_t *mutex) { - if (ptr) - free(ptr); + return 0; } -void -mowgli_allocator_init(void) +static int mowgli_null_mutex_destroy(mowgli_mutex_t *mutex) { - mowgli_allocator_malloc = mowgli_allocation_policy_create("malloc", mowgli_allocator_func_malloc, - mowgli_allocator_func_free); + return 0; } + +const mowgli_mutex_ops_t _mowgli_null_mutex_ops = { + .mutex_create = mowgli_null_mutex_create, + .mutex_lock = mowgli_null_mutex_lock, + .mutex_trylock = mowgli_null_mutex_trylock, + .mutex_unlock = mowgli_null_mutex_unlock, + .mutex_destroy = mowgli_null_mutex_destroy +}; diff --git a/src/libmowgli/thread/posix_mutexops.c b/src/libmowgli/thread/posix_mutexops.c new file mode 100644 index 0000000..5fb64e9 --- /dev/null +++ b/src/libmowgli/thread/posix_mutexops.c @@ -0,0 +1,115 @@ +/* + * libmowgli: A collection of useful routines for programming. + * posix_mutexops.c: POSIX Mutexes. + * + * Copyright (c) 2011 Wilcox Technologies, LLC <awilcox -at- wilcox-tech.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifndef _WIN32 + +/************* + * This implements native Sun/UnixWare threads. Some other SVR4-based + * environments attempted to make work-alikes, but those aren't guaranteed + * to be supported. This should work on SunOS 5.2 and UnixWare 7, and + * anything later. + *************/ +#if defined(__sun) || defined(__sco) + +static int mowgli_sun_mutex_create(mowgli_mutex_t *mutex) +{ + return mutex_init(&mutex->mutex, USYNC_THREAD, NULL); +} + +static int mowgli_sun_mutex_lock(mowgli_mutex_t *mutex) +{ + return mutex_lock(&mutex->mutex); +} + +static int mowgli_sun_mutex_trylock(mowgli_mutex_t *mutex) +{ + return mutex_trylock(&mutex->mutex); +} + +static int mowgli_sun_mutex_unlock(mowgli_mutex_t *mutex) +{ + return mutex_unlock(&mutex->mutex); +} + +static int mowgli_sun_mutex_destroy(mowgli_mutex_t *mutex) +{ + return mutex_destroy(&mutex->mutex); +} + +const mowgli_mutex_ops_t _mowgli_sun_mutex_ops = { + .mutex_create = mowgli_sun_mutex_create, + .mutex_lock = mowgli_sun_mutex_lock, + .mutex_trylock = mowgli_sun_mutex_trylock, + .mutex_unlock = mowgli_sun_mutex_unlock, + .mutex_destroy = mowgli_sun_mutex_destroy, +}; + +/************* + * This "default" implementation uses pthreads. Care has been taken to + * ensure it runs on POSIX 1003.4a (draft 4, aka DECthreads, aka what OSF/1, + * Tru64, Ultrix, CMU Mach, and HP-UX use) as well as POSIX 1003.1c-1995. + * As long as you don't try playing with the pthread_attr module or the + * scheduler routines (which are non-standard and broken anyway, IMO) then + * it should be relatively easy to maintian d4 compatibility without + * sacrificing any functionality. + *************/ +#elif !defined(MOWGLI_FEATURE_HAVE_NATIVE_MUTEXES) + +static int mowgli_posix_mutex_create(mowgli_mutex_t *mutex) +{ + return pthread_mutex_init(&mutex->mutex, NULL); +} + +static int mowgli_posix_mutex_lock(mowgli_mutex_t *mutex) +{ + return pthread_mutex_lock(&mutex->mutex); +} + +static int mowgli_posix_mutex_trylock(mowgli_mutex_t *mutex) +{ + return pthread_mutex_trylock(&mutex->mutex); +} + +static int mowgli_posix_mutex_unlock(mowgli_mutex_t *mutex) +{ + return pthread_mutex_unlock(&mutex->mutex); +} + +static int mowgli_posix_mutex_destroy(mowgli_mutex_t *mutex) +{ + return pthread_mutex_destroy(&mutex->mutex); +} + +const mowgli_mutex_ops_t _mowgli_posix_mutex_ops = { + .mutex_create = mowgli_posix_mutex_create, + .mutex_lock = mowgli_posix_mutex_lock, + .mutex_trylock = mowgli_posix_mutex_trylock, + .mutex_unlock = mowgli_posix_mutex_unlock, + .mutex_destroy = mowgli_posix_mutex_destroy, +}; + +#endif + +#endif diff --git a/src/libmowgli/thread/thread.h b/src/libmowgli/thread/thread.h new file mode 100644 index 0000000..f063217 --- /dev/null +++ b/src/libmowgli/thread/thread.h @@ -0,0 +1,78 @@ +/* + * libmowgli: A collection of useful routines for programming. + * thread.h: Cross-platform threading helper routines. + * + * Copyright (c) 2011 Wilcox Technologies, LLC <awilcox -at- wilcox-tech.com> + * Copyright (c) 2011, 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_THREAD_H__ +#define __MOWGLI_THREAD_H__ + +#ifdef MOWGLI_OS_UNIX_TYPE +# include <thread.h> +# define MOWGLI_FEATURE_HAVE_NATIVE_THREADS +# define MOWGLI_NATIVE_THREAD_DECL(name) thread_t (name) +#elif defined MOWGLI_OS_WIN +# define MOWGLI_FEATURE_HAVE_NATIVE_THREADS +# define MOWGLI_NATIVE_THREAD_DECL(name) HANDLE (name) +#else +# include <pthread.h> +#endif + +typedef struct { +#ifdef MOWGLI_FEATURE_HAVE_NATIVE_THREADS + MOWGLI_NATIVE_THREAD_DECL(thread); +#else + pthread_t thread; +#endif +} mowgli_thread_t; + +#ifdef MOWGLI_NATIVE_THREAD_DECL +# undef MOWGLI_NATIVE_THREAD_DECL +#endif + +typedef void *(*mowgli_thread_start_fn_t)(mowgli_thread_t *thread, void *userdata); + +/* + * Note: we should keep our thread interface light and minimal for best possible + * portability. Creating, ending, killing and cleanup functions are presently implemented, + * and cover approximately 99.999% of uses of thread APIs. --nenolod + */ +typedef struct { + int (*thread_create)(mowgli_thread_t *thread, mowgli_thread_start_fn_t start_fn, void *userdata); + void (*thread_exit)(mowgli_thread_t *thread); + void *(*thread_join)(mowgli_thread_t *thread); + void (*thread_kill)(mowgli_thread_t *thread); + void (*thread_destroy)(mowgli_thread_t *thread); +} mowgli_thread_ops_t; + +int mowgli_thread_create(mowgli_thread_t *thread, mowgli_thread_start_fn_t start_fn, void *userdata); +void mowgli_thread_exit(mowgli_thread_t *thread); +void *mowgli_thread_join(mowgli_thread_t *thread); +void mowgli_thread_kill(mowgli_thread_t *thread); +void mowgli_thread_destroy(mowgli_thread_t *thread); + +typedef enum { + MOWGLI_THREAD_POLICY_DEFAULT, + MOWGLI_THREAD_POLICY_DISABLED, +} mowgli_thread_policy_t; + +#endif + diff --git a/src/libmowgli/thread/win32_mutexops.c b/src/libmowgli/thread/win32_mutexops.c new file mode 100644 index 0000000..486992f --- /dev/null +++ b/src/libmowgli/thread/win32_mutexops.c @@ -0,0 +1,74 @@ +/* + * libmowgli: A collection of useful routines for programming. + * win32_mutexops.c: Windows mutex operations + * + * Copyright (c) 2011 Wilcox Technologies, LLC <awilcox -at- wilcox-tech.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + + +/************* + * This Windows implementation is guaranteed to work on Windows 95, + * Windows NT 4, and anything later. + *************/ +#if defined(_WIN32) + +static int mowgli_win32_mutex_create(mowgli_mutex_t *mutex) +{ + mutex->mutex = CreateMutex(NULL, FALSE, NULL); + if(mutex->mutex == NULL) + return GetLastError(); + + return 0; +} + +static int mowgli_win32_mutex_lock(mowgli_mutex_t *mutex) +{ + return WaitForSingleObject(mutex->mutex, INFINITE); +} + +static int mowgli_win32_mutex_trylock(mowgli_mutex_t *mutex) +{ + return WaitForSingleObject(mutex->mutex, 0); +} + +static int mowgli_win32_mutex_unlock(mowgli_mutex_t *mutex) +{ + if(ReleaseMutex(mutex->mutex) != 0) + return 0; + + return GetLastError(); +} + +static int mowgli_win32_mutex_destroy(mowgli_mutex_t *mutex) +{ + CloseHandle(mutex->mutex); + return 0; +} + +const mowgli_mutex_ops_t _mowgli_win32_mutex_ops = { + .mutex_create = mowgli_win32_mutex_create, + .mutex_lock = mowgli_win32_mutex_lock, + .mutex_trylock = mowgli_win32_mutex_trylock, + .mutex_unlock = mowgli_win32_mutex_unlock, + .mutex_destroy = mowgli_win32_mutex_destroy +}; + +#endif diff --git a/src/libmowgli/vio/Makefile b/src/libmowgli/vio/Makefile new file mode 100644 index 0000000..adbea96 --- /dev/null +++ b/src/libmowgli/vio/Makefile @@ -0,0 +1,15 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_VIO} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_VIO} + +SRCS = vio.c vio_sockets.c vio_openssl.c + +INCLUDES = vio.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/vio + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/vio/vio.c b/src/libmowgli/vio/vio.c new file mode 100644 index 0000000..ef4fb90 --- /dev/null +++ b/src/libmowgli/vio/vio.c @@ -0,0 +1,140 @@ +/* + * libmowgli: A collection of useful routines for programming. + * vio.c: Virtual I/O subsystem + * + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* How the VIO API works: + * + * - Return 0 in your error callback if you have nothing to report (non-fatal error or no error) + * - Return -1 in your callback if you have a fatal error + * - Return the length of bytes written or read, similar to the semantics of + * the read(3) or write(3) calls, if you are a read/write callback. + * + * These are just default implementations, you can change them to suit your needs. + */ + +static mowgli_heap_t *vio_heap = NULL; + +/* Change these to suit your needs for new VIO objects */ +mowgli_vio_ops_t mowgli_vio_default_ops = { + .socket = mowgli_vio_default_socket, + .bind = mowgli_vio_default_bind, + .listen = mowgli_vio_default_listen, + .accept = mowgli_vio_default_accept, + .connect = mowgli_vio_default_connect, + .read = mowgli_vio_default_read, + .write = mowgli_vio_default_write, + .sendto = mowgli_vio_default_sendto, + .recvfrom = mowgli_vio_default_recvfrom, + .error = mowgli_vio_default_error, + .close = mowgli_vio_default_close, + .seek = mowgli_vio_default_seek, + .tell = mowgli_vio_default_tell, +}; + +mowgli_vio_t * mowgli_vio_create(void *userdata) +{ + mowgli_vio_t *vio; + + if (!vio_heap) + vio_heap = mowgli_heap_create(sizeof(mowgli_vio_t), 64, BH_NOW); + + vio = mowgli_heap_alloc(vio_heap); + + mowgli_vio_init(vio, userdata); + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISONHEAP, true); + + return vio; +} + +void mowgli_vio_init(mowgli_vio_t *vio, void *userdata) +{ + vio->fd = -1; + + vio->flags = 0; + + /* Default ops */ + vio->ops = mowgli_vio_default_ops; + + vio->userdata = userdata; +} + +void mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop) +{ + vio->io = mowgli_pollable_create(eventloop, vio->fd, vio->userdata); + if (vio->io != NULL) + { + vio->eventloop = eventloop; + /* You're probably going to want this */ + mowgli_pollable_set_nonblocking(vio->io, true); + } + else + mowgli_log("Unable to create pollable with VIO object [%p], expect problems.", vio); +} + +void mowgli_vio_eventloop_detach(mowgli_vio_t *vio) +{ + return_if_fail(vio->io != NULL); + return_if_fail(vio->eventloop != NULL); + + mowgli_pollable_destroy(vio->eventloop, vio->io); +} + +void mowgli_vio_destroy(mowgli_vio_t *vio) +{ + mowgli_vio_eventloop_detach(vio); + + if (mowgli_vio_hasflag(vio, MOWGLI_VIO_FLAGS_ISONHEAP)) + mowgli_heap_free(vio_heap, vio); +} + +int mowgli_vio_err_errcode(mowgli_vio_t *vio, char *(*int_to_error)(int), int errcode) +{ + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; + vio->error.code = errcode; + mowgli_strlcpy(vio->error.string, int_to_error(errcode), sizeof(vio->error.string)); + return mowgli_vio_error(vio); +} + +#ifdef HAVE_OPENSSL + +int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode) +{ + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; + vio->error.code = errcode; + ERR_error_string_n(errcode, vio->error.string, sizeof(vio->error.string)); + return mowgli_vio_error(vio); +} + +#else + +int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode) +{ + vio->error.type = MOWGLI_VIO_ERR_ERRCODE; + vio->error.code = errcode; + mowgli_strlcpy(vio->error.string, "Unknown SSL error", sizeof(vio->error.string)); + return mowgli_vio_error(vio); +} + +#endif diff --git a/src/libmowgli/vio/vio.h b/src/libmowgli/vio/vio.h new file mode 100644 index 0000000..37b5c37 --- /dev/null +++ b/src/libmowgli/vio/vio.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_VIO_VIO_H__ +#define __MOWGLI_VIO_VIO_H__ + +/* Types and structs */ +typedef struct _mowgli_vio mowgli_vio_t; + +typedef enum { + MOWGLI_VIO_ERR_NONE, + MOWGLI_VIO_ERR_REMOTE_HANGUP, + MOWGLI_VIO_ERR_ERRCODE, + MOWGLI_VIO_ERR_API, + MOWGLI_VIO_ERR_CUSTOM, +} mowgli_vio_error_type_t; + +typedef enum { + MOWGLI_VIO_ERR_OP_NONE, + MOWGLI_VIO_ERR_OP_SOCKET, + MOWGLI_VIO_ERR_OP_LISTEN, + MOWGLI_VIO_ERR_OP_ACCEPT, + MOWGLI_VIO_ERR_OP_CONNECT, + MOWGLI_VIO_ERR_OP_READ, + MOWGLI_VIO_ERR_OP_WRITE, + MOWGLI_VIO_ERR_OP_BIND, + MOWGLI_VIO_ERR_OP_SEEK, + MOWGLI_VIO_ERR_OP_TELL, + MOWGLI_VIO_ERR_OP_OTHER, +} mowgli_vio_error_op_t; + +typedef struct _mowgli_vio_error { + mowgli_vio_error_op_t op; + mowgli_vio_error_type_t type; + int code; + char string[128]; +} mowgli_vio_error_t; + +typedef struct _mowgli_vio_sockaddr { + struct sockaddr_storage addr; + socklen_t addrlen; +} mowgli_vio_sockaddr_t; + +typedef struct _mowgli_vio_sockdata { + char host[39]; /* max length of IPv6 address */ + uint16_t port; +} mowgli_vio_sockdata_t; + +typedef int mowgli_vio_func_t(mowgli_vio_t *); +typedef int mowgli_vio_bind_connect_func_t(mowgli_vio_t *, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_read_func_t(mowgli_vio_t *, void *, size_t); +typedef int mowgli_vio_write_func_t(mowgli_vio_t *, const void *, size_t); +typedef int mowgli_vio_sendto_func_t(mowgli_vio_t *, const void *, size_t, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_recvfrom_func_t(mowgli_vio_t *, void *, size_t, mowgli_vio_sockaddr_t *); +typedef int mowgli_vio_connect_func_t(mowgli_vio_t *); +typedef int mowgli_vio_accept_func_t(mowgli_vio_t *, mowgli_vio_t *); +typedef int mowgli_vio_listen_func_t(mowgli_vio_t *, int); +typedef int mowgli_vio_socket_func_t(mowgli_vio_t *, int, int, int); +typedef int mowgli_vio_seek_func_t(mowgli_vio_t *, long, int); + +typedef struct { + mowgli_vio_socket_func_t *socket; + mowgli_vio_bind_connect_func_t *bind; + mowgli_vio_bind_connect_func_t *connect; + mowgli_vio_listen_func_t *listen; + mowgli_vio_accept_func_t *accept; + mowgli_vio_read_func_t *read; + mowgli_vio_write_func_t *write; + mowgli_vio_sendto_func_t *sendto; + mowgli_vio_recvfrom_func_t *recvfrom; + mowgli_vio_func_t *error; + mowgli_vio_func_t *close; + mowgli_vio_seek_func_t *seek; + mowgli_vio_func_t *tell; +} mowgli_vio_ops_t; + +struct _mowgli_vio { + mowgli_vio_ops_t ops; + + mowgli_eventloop_io_t *io; + mowgli_descriptor_t fd; + + mowgli_eventloop_t *eventloop; + + mowgli_vio_sockaddr_t addr; + + mowgli_vio_error_t error; + + int flags; + + void *userdata; + void *privdata; +}; + +typedef struct _mowgli_vio_ssl_settings { + char cert_path[FILENAME_MAX]; + char privatekey_path[FILENAME_MAX]; + int ssl_version; + int (*password_func)(char *, int, int, void *); + int (*verify_func)(int, void *); +} mowgli_vio_ssl_settings_t; + + +/* Flags */ +#define MOWGLI_VIO_FLAGS_ISCONNECTING 0x00001 +#define MOWGLI_VIO_FLAGS_ISSSLCONNECTING 0x00002 +#define MOWGLI_VIO_FLAGS_ISCLOSED 0x00004 + +#define MOWGLI_VIO_FLAGS_ISCLIENT 0x00008 +#define MOWGLI_VIO_FLAGS_ISSERVER 0x00010 + +#define MOWGLI_VIO_FLAGS_ISONHEAP 0x00020 + +#define MOWGLI_VIO_FLAGS_NEEDREAD 0x00040 +#define MOWGLI_VIO_FLAGS_NEEDWRITE 0x00080 + +/* SSL flags */ +#define MOWGLI_VIO_SSLFLAGS_SSLV2 0x00001 +#define MOWGLI_VIO_SSLFLAGS_SSLV3 0x00002 +#define MOWGLI_VIO_SSLFLAGS_TLSV10 0x00004 +#define MOWGLI_VIO_SSLFLAGS_TLSV11 0x00008 +#define MOWGLI_VIO_SSLFLAGS_TLSV12 0x00010 + + +/* Flag setting/getting */ +static inline bool mowgli_vio_hasflag(mowgli_vio_t *vio, int flag) +{ + return (vio->flags & flag) != 0 ? true : false; +} + +static inline void mowgli_vio_setflag(mowgli_vio_t *vio, int flag, bool setting) +{ + if (setting) + vio->flags |= flag; + else + vio->flags &= ~flag; +} + + +/* Macros */ +#define MOWGLI_VIO_SET_CLOSED(v) \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCONNECTING, false); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISCLOSED, true); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, false); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDREAD, false); \ + mowgli_vio_setflag(v, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + + +/* Decls */ +extern mowgli_vio_t * mowgli_vio_create(void *userdata); +extern void mowgli_vio_init(mowgli_vio_t *vio, void *userdata); +extern void mowgli_vio_destroy(mowgli_vio_t *vio); + +extern void mowgli_vio_eventloop_attach(mowgli_vio_t *vio, mowgli_eventloop_t *eventloop); +extern void mowgli_vio_eventloop_detach(mowgli_vio_t *vio); + +extern mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port); +extern mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size); +extern int mowgli_vio_sockaddr_info(const mowgli_vio_sockaddr_t *addr, mowgli_vio_sockdata_t *data); + +extern int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto); +extern int mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); +extern int mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog); +extern int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); +extern int mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); +extern int mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len); +extern int mowgli_vio_default_write(mowgli_vio_t *vio, const void *buffer, size_t len); +extern int mowgli_vio_default_sendto(mowgli_vio_t *vio, const void *buffer, size_t len, mowgli_vio_sockaddr_t *addr); +extern int mowgli_vio_default_recvfrom(mowgli_vio_t *vio, void *buffer, size_t len, mowgli_vio_sockaddr_t *addr); +extern int mowgli_vio_default_error(mowgli_vio_t *vio); +extern int mowgli_vio_default_close(mowgli_vio_t *vio); +extern int mowgli_vio_default_seek(mowgli_vio_t *vio, long offset, int whence); +extern int mowgli_vio_default_tell(mowgli_vio_t *vio); + +extern int mowgli_vio_err_errcode(mowgli_vio_t *vio, char *(*int_to_error)(int), int errcode); +extern int mowgli_vio_err_sslerrcode(mowgli_vio_t *vio, int errcode); + +extern int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings); +/* These are void ptr's so they can be null ops if SSL isn't available */ +extern void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio); +extern void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio); + +extern mowgli_vio_ops_t mowgli_vio_default_ops; + + +/* Sundry operations on vio functables */ +#define mowgli_vio_set_op(vio, op, func) vio->ops.op = func; + +#define mowgli_vio_socket(vio, ...) vio->ops.socket(vio, __VA_ARGS__) +#define mowgli_vio_listen(vio, ...) vio->ops.listen(vio, __VA_ARGS__) +#define mowgli_vio_bind(vio, ...) vio->ops.bind(vio, __VA_ARGS__) +#define mowgli_vio_accept(vio, ...) vio->ops.accept(vio, __VA_ARGS__) +#define mowgli_vio_connect(vio, ...) vio->ops.connect(vio, __VA_ARGS__) +#define mowgli_vio_read(vio, ...) vio->ops.read(vio, __VA_ARGS__) +#define mowgli_vio_write(vio, ...) vio->ops.write(vio, __VA_ARGS__) +#define mowgli_vio_sendto(vio, ...) vio->ops.sendto(vio, __VA_ARGS__) +#define mowgli_vio_recvfrom(vio, ...) vio->ops.recvfrom(vio, __VA_ARGS__) +#define mowgli_vio_error(vio) vio->ops.error(vio); +#define mowgli_vio_close(vio) vio->ops.close(vio); +#define mowgli_vio_seek(vio, ...) vio->ops.seek(vio, __VA_ARGS__) +#define mowgli_vio_tell(vio) vio->ops.tell(vio) + +#endif + diff --git a/src/libmowgli/vio/vio_openssl.c b/src/libmowgli/vio/vio_openssl.c new file mode 100644 index 0000000..75c83e4 --- /dev/null +++ b/src/libmowgli/vio/vio_openssl.c @@ -0,0 +1,447 @@ +/* + * libmowgli: A collection of useful routines for programming. + * vio_openssl.c: OpenSSL routines built on VIO + * + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +/* Note these routines are just defaults for clients -- if you have more + * specific needs, you should write your own implementation (that is the + * whole point of vio) + */ + +#ifdef HAVE_OPENSSL + +typedef struct { + SSL *ssl_handle; + SSL_CTX *ssl_context; + mowgli_vio_ssl_settings_t settings; +} mowgli_ssl_connection_t; + +static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr); +static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog); +static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio); +static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection); +static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len); +static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len); +static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len); +static int mowgli_vio_openssl_close(mowgli_vio_t *vio); + +static mowgli_heap_t *ssl_heap = NULL; + +static bool openssl_init = false; + +int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +{ + mowgli_ssl_connection_t *connection; + + if (!ssl_heap) + ssl_heap = mowgli_heap_create(sizeof(mowgli_ssl_connection_t), 64, BH_NOW); + + connection = mowgli_heap_alloc(ssl_heap); + vio->privdata = connection; + + if (settings) + memcpy(&connection->settings, settings, sizeof(mowgli_vio_ssl_settings_t)); + else + /* Greatest compat without being terribly insecure */ + connection->settings.ssl_version = MOWGLI_VIO_SSLFLAGS_SSLV3; + + /* Change ops */ + mowgli_vio_set_op(vio, connect, mowgli_vio_openssl_connect); + mowgli_vio_set_op(vio, read, mowgli_vio_openssl_read); + mowgli_vio_set_op(vio, write, mowgli_vio_openssl_write); + mowgli_vio_set_op(vio, close, mowgli_vio_openssl_close); + mowgli_vio_set_op(vio, accept, mowgli_vio_openssl_accept); + mowgli_vio_set_op(vio, listen, mowgli_vio_openssl_listen); + + /* SSL setup */ + if (!openssl_init) + { + openssl_init = true; + SSL_library_init(); + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + } + + return 0; +} + +/* Returns void so they can be stubs */ +void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +{ + mowgli_ssl_connection_t *connection = vio->privdata; + return connection->ssl_handle; +} + +void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +{ + mowgli_ssl_connection_t *connection = vio->privdata; + return connection->ssl_context; +} + +static int mowgli_vio_openssl_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + mowgli_ssl_connection_t *connection = vio->privdata; + + if (connect(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, true); + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; + } + } + + memcpy(&vio->addr.addr, &addr->addr, addr->addrlen); + vio->addr.addrlen = addr->addrlen; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLIENT, true); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, false); + + /* Non-blocking socket, begin handshake */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + return mowgli_vio_openssl_client_handshake(vio, connection); +} + +static int mowgli_vio_openssl_listen(mowgli_vio_t *vio, int backlog) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; + mowgli_ssl_connection_t *connection = vio->privdata; + const SSL_METHOD *method; + + switch (connection->settings.ssl_version) + { + case MOWGLI_VIO_SSLFLAGS_SSLV2: + method = SSLv23_server_method(); + break; + case MOWGLI_VIO_SSLFLAGS_SSLV3: + method = SSLv3_server_method(); + break; + case MOWGLI_VIO_SSLFLAGS_TLSV10: + case MOWGLI_VIO_SSLFLAGS_TLSV11: + case MOWGLI_VIO_SSLFLAGS_TLSV12: + method = TLSv1_server_method(); + break; + default: + /* Compat method */ + method = SSLv23_server_method(); + } + + connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + if (connection->ssl_context == NULL) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + SSL_set_accept_state(connection->ssl_handle); + SSL_CTX_set_options(connection->ssl_context, SSL_OP_SINGLE_DH_USE); + + if (connection->settings.password_func) + { + SSL_CTX_set_default_passwd_cb(connection->ssl_context, connection->settings.password_func); + SSL_CTX_set_default_passwd_cb_userdata(connection->ssl_context, vio->userdata); + } + + if (SSL_CTX_use_certificate_file(connection->ssl_context, connection->settings.cert_path, SSL_FILETYPE_PEM) != 1) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + if (SSL_CTX_use_PrivateKey_file(connection->ssl_context, connection->settings.privatekey_path, SSL_FILETYPE_PEM) != 1) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + if (listen(vio->fd, backlog) != 0) + return mowgli_vio_err_errcode(vio, strerror, errno); + + if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true); + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + + return 0; +} + +static int mowgli_vio_openssl_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) +{ + int fd; + int ret; + mowgli_ssl_connection_t *connection = vio->privdata; + mowgli_ssl_connection_t *newconnection; + + vio->error.op = MOWGLI_VIO_ERR_OP_ACCEPT; + + if (!newvio) + { + const char errstr[] = "accept not called with valid new VIO object"; + vio->error.type = MOWGLI_VIO_ERR_API; + mowgli_strlcpy(vio->error.string, errstr, sizeof(errstr)); + return mowgli_vio_error(vio); + } + + if ((fd = accept(vio->fd, (struct sockaddr *)&newvio->addr.addr, &(newvio->addr.addrlen))) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else + return 0; + } + + newvio->fd = fd; + + mowgli_vio_openssl_setssl(newvio, &connection->settings); + newconnection = newvio->privdata; + newconnection->ssl_context = connection->ssl_context; + newconnection->ssl_handle = SSL_new(newconnection->ssl_context); + + if (!SSL_set_fd(newconnection->ssl_handle, fd)) + return mowgli_vio_err_sslerrcode(newvio, ERR_get_error()); + + if ((ret = SSL_accept(newconnection->ssl_handle)) != 1) + { + unsigned long err; + + switch (SSL_get_error(newconnection->ssl_handle, ret)) + { + case SSL_ERROR_WANT_READ: + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + return 0; + case SSL_ERROR_WANT_WRITE: + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + return 0; + case SSL_ERROR_ZERO_RETURN: + return 0; + case SSL_ERROR_SYSCALL: + return mowgli_vio_err_errcode(newvio, strerror, errno); + default: + err = ERR_get_error(); + break; + } + + if(err > 0) + { + errno = EIO; + return mowgli_vio_err_errcode(vio, strerror, errno); + } + + return -1; + } + + mowgli_vio_setflag(newvio, MOWGLI_VIO_FLAGS_ISCLIENT, true); + mowgli_vio_setflag(newvio, MOWGLI_VIO_FLAGS_ISSERVER, false); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +static int mowgli_vio_openssl_client_handshake(mowgli_vio_t *vio, mowgli_ssl_connection_t *connection) +{ + int ret; + const SSL_METHOD *method; + + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + + switch (connection->settings.ssl_version) + { + case MOWGLI_VIO_SSLFLAGS_SSLV2: + method = SSLv23_client_method(); + break; + case MOWGLI_VIO_SSLFLAGS_SSLV3: + method = SSLv3_client_method(); + break; + case MOWGLI_VIO_SSLFLAGS_TLSV10: + case MOWGLI_VIO_SSLFLAGS_TLSV11: + case MOWGLI_VIO_SSLFLAGS_TLSV12: + method = TLSv1_client_method(); + break; + default: + /* Compat method */ + method = SSLv23_client_method(); + } + + /* Cast is to eliminate an excessively bogus warning on old OpenSSL --Elizacat */ + connection->ssl_context = SSL_CTX_new((SSL_METHOD *)method); + if (connection->ssl_context == NULL) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + connection->ssl_handle = SSL_new(connection->ssl_context); + if (connection->ssl_handle == NULL) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + SSL_set_connect_state(connection->ssl_handle); + + if (!SSL_set_fd(connection->ssl_handle, vio->fd)) + return mowgli_vio_err_sslerrcode(vio, ERR_get_error()); + + /* XXX not what we want for blocking sockets if they're in use! */ + SSL_CTX_set_mode(connection->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); + + if ((ret = SSL_connect(connection->ssl_handle)) != 1) + { + int err = SSL_get_error(connection->ssl_handle, ret); + if (err == SSL_ERROR_WANT_READ) + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + else if (err == SSL_ERROR_WANT_WRITE) + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + else if (err == SSL_ERROR_WANT_CONNECT) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); + return 0; + } + else + return mowgli_vio_err_sslerrcode(vio, err); + } + + /* Connected */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSSLCONNECTING, false); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +#define MOWGLI_VIO_SSL_DOREAD true +#define MOWGLI_VIO_SSL_DOWRITE false + +static int mowgli_vio_openssl_read(mowgli_vio_t *vio, void *buffer, size_t len) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_READ; + return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOREAD, vio, buffer, NULL, len); +} + +static int mowgli_vio_openssl_write(mowgli_vio_t *vio, const void *buffer, size_t len) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; + return mowgli_openssl_read_or_write(MOWGLI_VIO_SSL_DOWRITE, vio, NULL, buffer, len); +} + +static int mowgli_openssl_read_or_write(bool read, mowgli_vio_t *vio, void *readbuf, const void *writebuf, size_t len) +{ + mowgli_ssl_connection_t *connection = vio->privdata; + int ret; + unsigned long err; + + /* We are connected */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + + if (mowgli_vio_hasflag(vio, MOWGLI_VIO_FLAGS_ISSSLCONNECTING)) + return mowgli_vio_openssl_client_handshake(vio, connection); + + return_val_if_fail(connection->ssl_handle != NULL, -1); + + if(read) + ret = (int)SSL_read(connection->ssl_handle, readbuf, len); + else + ret = (int)SSL_write(connection->ssl_handle, writebuf, len); + + if (ret < 0) + { + switch (SSL_get_error(connection->ssl_handle, ret)) + { + case SSL_ERROR_WANT_READ: + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + return 0; + case SSL_ERROR_WANT_WRITE: + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + return 0; + case SSL_ERROR_ZERO_RETURN: + return 0; + case SSL_ERROR_SYSCALL: + if((err = ERR_get_error()) == 0) + { + vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; + mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, true); + + return mowgli_vio_error(vio); + } + + break; + + default: + err = ERR_get_error(); + break; + } + + if(err > 0) + { + errno = EIO; + return mowgli_vio_err_errcode(vio, strerror, errno); + } + + /* idk lol */ + return -1; + } + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return ret; +} + +static int mowgli_vio_openssl_close(mowgli_vio_t *vio) +{ + mowgli_ssl_connection_t *connection = vio->privdata; + + return_val_if_fail(connection->ssl_handle != NULL, -1); + + SSL_shutdown(connection->ssl_handle); + SSL_free(connection->ssl_handle); + SSL_CTX_free(connection->ssl_context); + + mowgli_heap_free(ssl_heap, connection); + + MOWGLI_VIO_SET_CLOSED(vio); + + close(vio->fd); + return 0; +} + +#else + +int mowgli_vio_openssl_setssl(mowgli_vio_t *vio, mowgli_vio_ssl_settings_t *settings) +{ + mowgli_log("OpenSSL requested on a VIO object, but mowgli was built without OpenSSL support..."); + return -1; +} + +void * mowgli_vio_openssl_getsslhandle(mowgli_vio_t *vio) +{ + mowgli_log("Cannot get VIO SSL handle as libmowgli was built without OpenSSL support"); + return NULL; +} + +void * mowgli_vio_openssl_getsslcontext(mowgli_vio_t *vio) +{ + mowgli_log("Cannot get VIO SSL context as libmowgli was built without OpenSSL support"); + return NULL; +} + +#endif + diff --git a/src/libmowgli/vio/vio_sockets.c b/src/libmowgli/vio/vio_sockets.c new file mode 100644 index 0000000..e36080b --- /dev/null +++ b/src/libmowgli/vio/vio_sockets.c @@ -0,0 +1,423 @@ +/* + * libmowgli: A collection of useful routines for programming. + * vio-sockets.c: Plain socket I/O routines for VIO. + * + * Copyright (c) 2012 Elizabeth J. Myers. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +int mowgli_vio_default_socket(mowgli_vio_t *vio, int family, int type, int proto) +{ + int fd; + + vio->error.op = MOWGLI_VIO_ERR_OP_SOCKET; + + /* We can't call socket with AF_UNSPEC on most platforms >_> */ + if (family == AF_UNSPEC) + family = AF_INET6; /* This is fine, IPv4 will still work via a 6to4 mapping */ + + if ((fd = socket(family, type, proto)) == -1) + return mowgli_vio_err_errcode(vio, strerror, errno); + + vio->fd = fd; + + if (family == SOCK_STREAM) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, false); + } + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +int mowgli_vio_default_bind(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_BIND; + + if (bind(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) != 0) + return mowgli_vio_err_errcode(vio, strerror, errno); + + memcpy(&vio->addr.addr, &addr->addr, sizeof(struct sockaddr_storage)); + vio->addr.addrlen = addr->addrlen; + + return 0; +} + +int mowgli_vio_default_listen(mowgli_vio_t *vio, int backlog) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_LISTEN; + + if (listen(vio->fd, backlog) < 0) + return mowgli_vio_err_errcode(vio, strerror, errno); + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, true); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLIENT, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, false); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +int mowgli_vio_default_accept(mowgli_vio_t *vio, mowgli_vio_t *newvio) +{ + int fd; + + vio->error.op = MOWGLI_VIO_ERR_OP_ACCEPT; + + if (!newvio) + { + const char errstr[] = "accept not called with valid new VIO object"; + vio->error.type = MOWGLI_VIO_ERR_API; + mowgli_strlcpy(vio->error.string, errstr, sizeof(errstr)); + return mowgli_vio_error(vio); + } + + if ((fd = accept(vio->fd, (struct sockaddr *)&newvio->addr.addr, &(newvio->addr.addrlen))) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else + return 0; + } + + newvio->fd = fd; + + /* The new VIO object is most certainly not a server */ + mowgli_vio_setflag(newvio, MOWGLI_VIO_FLAGS_ISCLIENT, true); + mowgli_vio_setflag(newvio, MOWGLI_VIO_FLAGS_ISSERVER, false); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +int mowgli_vio_default_connect(mowgli_vio_t *vio, mowgli_vio_sockaddr_t *addr) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_CONNECT; + + if (connect(vio->fd, (struct sockaddr *)&addr->addr, addr->addrlen) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + return mowgli_vio_err_errcode(vio, strerror, errno); + else + return 0; + } + + /* XXX -- overwrites if we already used bind -- not terribly concerning as this is + * more interesting --Elizabeth */ + memcpy(&vio->addr.addr, &addr->addr, sizeof(struct sockaddr_storage)); + vio->addr.addrlen = addr->addrlen; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLIENT, true); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISSERVER, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, true); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, false); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return 0; +} + +int mowgli_vio_default_read(mowgli_vio_t *vio, void *buffer, size_t len) +{ + int ret; + + vio->error.op = MOWGLI_VIO_ERR_OP_READ; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + + if ((ret = (int)recv(vio->fd, buffer, len, 0)) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + return mowgli_vio_err_errcode(vio, strerror, errno); + } + else if (errno != 0) + { + /* Further reads unnecessary */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + return 0; + } + + if (ret == 0) + { + vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; + mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); + + MOWGLI_VIO_SET_CLOSED(vio); + + return mowgli_vio_error(vio); + } + } + + /* Do this for edge-triggered interfaces */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return ret; +} + +int mowgli_vio_default_write(mowgli_vio_t *vio, const void *buffer, size_t len) +{ + int ret; + + vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + + if ((ret = (int)send(vio->fd, buffer, len, 0)) == -1) + { + if (!mowgli_eventloop_ignore_errno(errno)) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + return mowgli_vio_err_errcode(vio, strerror, errno); + } + else + { + /* Further writes unnecessary */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + return 0; + } + } + + /* Set this for edge-triggered interfaces */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return ret; +} + +int mowgli_vio_default_sendto(mowgli_vio_t *vio, const void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) +{ + int ret; + + vio->error.op = MOWGLI_VIO_ERR_OP_WRITE; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + + if ((ret = (int)sendto(vio->fd, buffer, len, 0, (struct sockaddr *)&addr->addr, addr->addrlen)) == -1) + { + if (!mowgli_eventloop_ignore_errno(errno)) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + return mowgli_vio_err_errcode(vio, strerror, errno); + } + else + { + /* Further writes unnecessary */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, false); + return 0; + } + } + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDWRITE, true); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return ret; +} + +int mowgli_vio_default_recvfrom(mowgli_vio_t *vio, void *buffer, size_t len, mowgli_vio_sockaddr_t *addr) +{ + int ret; + + vio->error.op = MOWGLI_VIO_ERR_OP_READ; + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + + if ((ret = (int)recvfrom(vio->fd, buffer, len, 0, (struct sockaddr *)&addr->addr, &addr->addrlen)) < 0) + { + if (!mowgli_eventloop_ignore_errno(errno)) + { + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + return mowgli_vio_err_errcode(vio, strerror, errno); + } + else if (errno != 0) + { + /* Further reads unnecessary */ + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, false); + return 0; + } + + if (ret == 0) + { + vio->error.type = MOWGLI_VIO_ERR_REMOTE_HANGUP; + mowgli_strlcpy(vio->error.string, "Remote host closed the socket", sizeof(vio->error.string)); + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCONNECTING, false); + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_ISCLOSED, true); + + return mowgli_vio_error(vio); + } + } + + mowgli_vio_setflag(vio, MOWGLI_VIO_FLAGS_NEEDREAD, true); + + vio->error.op = MOWGLI_VIO_ERR_OP_NONE; + return ret; +} + +int mowgli_vio_default_error(mowgli_vio_t *vio) +{ + const char *errtype; + + switch (vio->error.op) + { + case MOWGLI_VIO_ERR_OP_READ: + errtype = "Read"; + break; + case MOWGLI_VIO_ERR_OP_WRITE: + errtype = "Write"; + break; + case MOWGLI_VIO_ERR_OP_LISTEN: + errtype = "Listen"; + break; + case MOWGLI_VIO_ERR_OP_ACCEPT: + errtype = "Accept"; + break; + case MOWGLI_VIO_ERR_OP_CONNECT: + errtype = "Connect"; + break; + case MOWGLI_VIO_ERR_OP_SOCKET: + errtype = "Socket"; + break; + case MOWGLI_VIO_ERR_OP_BIND: + errtype = "Bind"; + break; + case MOWGLI_VIO_ERR_OP_OTHER: + errtype = "Application"; + break; + default: + errtype = "Generic/Unknown"; + } + + mowgli_log("%s error: %s\n", errtype, vio->error.string); + + return -1; +} + +int mowgli_vio_default_close(mowgli_vio_t *vio) +{ + MOWGLI_VIO_SET_CLOSED(vio); +#ifndef _WIN32 + close(vio->fd); +#else + closesocket(vio->fd); +#endif + return 0; +} + +int mowgli_vio_default_seek(mowgli_vio_t *vio, long offset, int whence) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_SEEK; + errno = ENOSYS; + return mowgli_vio_err_errcode(vio, strerror, errno); +} + +int mowgli_vio_default_tell(mowgli_vio_t *vio) +{ + vio->error.op = MOWGLI_VIO_ERR_OP_TELL; + errno = ENOSYS; + return mowgli_vio_err_errcode(vio, strerror, errno); +} + +/* Generate a mowgli_sockaddr_t struct */ +mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_create(mowgli_vio_sockaddr_t *naddr, int proto, const char *addr, int port) +{ + struct sockaddr_storage saddr; + + if (naddr == NULL) + naddr = mowgli_alloc(sizeof(mowgli_vio_sockaddr_t)); + + if (proto == AF_INET) + { + struct sockaddr_in *addr_in = (struct sockaddr_in *)&saddr; + + addr_in->sin_family = proto; + addr_in->sin_port = htons(port); + if (addr != NULL) + { + if (inet_pton(proto, addr, &addr_in->sin_addr) != 1) + mowgli_log("Error with inet_pton!"); + } + + memcpy(&naddr->addr, &saddr, sizeof(struct sockaddr_in)); + naddr->addrlen = sizeof(struct sockaddr_in); + } + else if (proto == AF_INET6) + { + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&saddr; + + addr_in6->sin6_family = proto; + addr_in6->sin6_port = htons(port); + if (addr != NULL) + { + if (inet_pton(proto, addr, &addr_in6->sin6_addr) != 1) + mowgli_log("Error with inet_pton!"); + } + + memcpy(&naddr->addr, &saddr, sizeof(struct sockaddr_in6)); + naddr->addrlen = sizeof(struct sockaddr_in6); + } + else + naddr = NULL; + + return naddr; +} + +mowgli_vio_sockaddr_t * mowgli_vio_sockaddr_from_struct(mowgli_vio_sockaddr_t *naddr, const void *addr, socklen_t size) +{ + const struct sockaddr_storage *saddr = addr; + + return_val_if_fail(addr != NULL, NULL); + return_val_if_fail(saddr->ss_family == AF_INET || saddr->ss_family == AF_INET6, NULL); + + if (naddr == NULL) + naddr = mowgli_alloc(sizeof(mowgli_vio_sockaddr_t)); + memcpy(&naddr->addr, saddr, size); + naddr->addrlen = size; + + return naddr; +} + +int mowgli_vio_sockaddr_info(const mowgli_vio_sockaddr_t *addr, mowgli_vio_sockdata_t *data) +{ + const void *sockptr; + const struct sockaddr *saddr = (const struct sockaddr *)&addr->addr; + + if (saddr->sa_family == AF_INET) + { + const struct sockaddr_in *saddr = (const struct sockaddr_in *)&addr->addr; + data->port = ntohs(saddr->sin_port); + sockptr = &saddr->sin_addr; + } + else if (saddr->sa_family == AF_INET6) + { + const struct sockaddr_in6 *saddr = (const struct sockaddr_in6 *)&addr->addr; + data->port = ntohs(saddr->sin6_port); + sockptr = &saddr->sin6_addr; + } + else + return -1; + + if (inet_ntop(saddr->sa_family, sockptr, data->host, sizeof(data->host)) == NULL) + return -1; + + return 0; +} |