summaryrefslogtreecommitdiff
path: root/src/libmowgli
diff options
context:
space:
mode:
authorAndrew Shadura <andrew@shadura.me>2014-01-28 15:21:50 +0100
committerAndrew Shadura <andrew@shadura.me>2014-01-28 15:21:50 +0100
commit51addbcf27d7b06dae80a0e39e5f5f83e94dd8ae (patch)
tree3d00bef2d26f97257ec6f4835505cd300054a1e3 /src/libmowgli
parent1ed00f1a2893b43195f3fc747988da0bf6006797 (diff)
Update to libmowgli 2.0.0
Diffstat (limited to 'src/libmowgli')
-rw-r--r--src/libmowgli/Makefile80
-rw-r--r--src/libmowgli/base/Makefile29
-rw-r--r--src/libmowgli/base/argstack.c (renamed from src/libmowgli/mowgli_argstack.c)4
-rw-r--r--src/libmowgli/base/argstack.h (renamed from src/libmowgli/mowgli_argstack.h)4
-rw-r--r--src/libmowgli/base/bitvector.c (renamed from src/libmowgli/mowgli_bitvector.c)4
-rw-r--r--src/libmowgli/base/bitvector.h (renamed from src/libmowgli/mowgli_bitvector.h)4
-rw-r--r--src/libmowgli/base/formatter.c (renamed from src/libmowgli/mowgli_formatter.c)2
-rw-r--r--src/libmowgli/base/formatter.h (renamed from src/libmowgli/mowgli_formatter.h)2
-rw-r--r--src/libmowgli/base/hash.c (renamed from src/libmowgli/mowgli_hash.c)14
-rw-r--r--src/libmowgli/base/hash.h (renamed from src/libmowgli/mowgli_hash.h)2
-rw-r--r--src/libmowgli/base/hook.c (renamed from src/libmowgli/mowgli_hook.c)6
-rw-r--r--src/libmowgli/base/hook.h (renamed from src/libmowgli/mowgli_hook.h)4
-rw-r--r--src/libmowgli/base/memslice.c146
-rw-r--r--src/libmowgli/base/memslice.h27
-rw-r--r--src/libmowgli/base/mowgli_signal.c (renamed from src/libmowgli/mowgli_signal.c)1
-rw-r--r--src/libmowgli/base/mowgli_signal.h (renamed from src/libmowgli/mowgli_signal.h)2
-rw-r--r--src/libmowgli/base/random.c (renamed from src/libmowgli/mowgli_random.c)10
-rw-r--r--src/libmowgli/base/random.h (renamed from src/libmowgli/mowgli_random.h)4
-rw-r--r--src/libmowgli/container/Makefile23
-rw-r--r--src/libmowgli/container/dictionary.c (renamed from src/libmowgli/mowgli_dictionary.c)53
-rw-r--r--src/libmowgli/container/dictionary.h (renamed from src/libmowgli/mowgli_dictionary.h)38
-rw-r--r--src/libmowgli/container/index.c (renamed from src/libmowgli/mowgli_index.c)16
-rw-r--r--src/libmowgli/container/index.h (renamed from src/libmowgli/mowgli_index.h)0
-rw-r--r--src/libmowgli/container/list.c (renamed from src/libmowgli/mowgli_list.c)34
-rw-r--r--src/libmowgli/container/list.h (renamed from src/libmowgli/mowgli_list.h)12
-rw-r--r--src/libmowgli/container/patricia.c (renamed from src/libmowgli/mowgli_patricia.c)51
-rw-r--r--src/libmowgli/container/patricia.h (renamed from src/libmowgli/mowgli_patricia.h)9
-rw-r--r--src/libmowgli/container/queue.c (renamed from src/libmowgli/mowgli_queue.c)26
-rw-r--r--src/libmowgli/container/queue.h (renamed from src/libmowgli/mowgli_queue.h)4
-rw-r--r--src/libmowgli/dns/Makefile20
-rw-r--r--src/libmowgli/dns/dns.c82
-rw-r--r--src/libmowgli/dns/dns.h96
-rw-r--r--src/libmowgli/dns/dns_evloop_res.c1017
-rw-r--r--src/libmowgli/dns/dns_evloop_res.h44
-rw-r--r--src/libmowgli/dns/dns_evloop_reslib.c1102
-rw-r--r--src/libmowgli/dns/dns_evloop_reslib.h112
-rw-r--r--src/libmowgli/dns/dns_evloop_reslist_win32.c97
-rw-r--r--src/libmowgli/eventloop/Makefile14
-rw-r--r--src/libmowgli/eventloop/epoll_pollops.c198
-rw-r--r--src/libmowgli/eventloop/eventloop.c170
-rw-r--r--src/libmowgli/eventloop/eventloop.h259
-rw-r--r--src/libmowgli/eventloop/helper.c230
-rw-r--r--src/libmowgli/eventloop/kqueue_pollops.c189
-rw-r--r--src/libmowgli/eventloop/null_pollops.c124
-rw-r--r--src/libmowgli/eventloop/poll_pollops.c229
-rw-r--r--src/libmowgli/eventloop/pollable.c88
-rw-r--r--src/libmowgli/eventloop/ports_pollops.c186
-rw-r--r--src/libmowgli/eventloop/qnx_pollops.c200
-rw-r--r--src/libmowgli/eventloop/select_pollops.c203
-rw-r--r--src/libmowgli/eventloop/timer.c172
-rw-r--r--src/libmowgli/eventloop/windows_pollops.c276
-rw-r--r--src/libmowgli/ext/Makefile25
-rw-r--r--src/libmowgli/ext/confparse.c436
-rw-r--r--src/libmowgli/ext/confparse.h45
-rw-r--r--src/libmowgli/ext/error_backtrace.c (renamed from src/libmowgli/mowgli_error_backtrace.c)10
-rw-r--r--src/libmowgli/ext/error_backtrace.h (renamed from src/libmowgli/mowgli_error_backtrace.h)2
-rw-r--r--src/libmowgli/ext/getopt_long.c461
-rw-r--r--src/libmowgli/ext/getopt_long.h69
-rw-r--r--src/libmowgli/ext/global_storage.c (renamed from src/libmowgli/mowgli_global_storage.c)25
-rw-r--r--src/libmowgli/ext/global_storage.h (renamed from src/libmowgli/mowgli_global_storage.h)4
-rw-r--r--src/libmowgli/ext/proctitle.c311
-rw-r--r--src/libmowgli/ext/proctitle.h23
-rw-r--r--src/libmowgli/ext/program_opts.c191
-rw-r--r--src/libmowgli/ext/program_opts.h (renamed from src/libmowgli/mowgli_allocation_policy.h)43
-rw-r--r--src/libmowgli/linebuf/Makefile15
-rw-r--r--src/libmowgli/linebuf/linebuf.c292
-rw-r--r--src/libmowgli/linebuf/linebuf.h79
-rw-r--r--src/libmowgli/module/Makefile15
-rw-r--r--src/libmowgli/module/loader_posix.c (renamed from src/libmowgli/mowgli_module_posix.c)2
-rw-r--r--src/libmowgli/module/loader_win32.c (renamed from src/libmowgli/mowgli_module_win32.c)2
-rw-r--r--src/libmowgli/module/module.h (renamed from src/libmowgli/mowgli_module.h)2
-rw-r--r--src/libmowgli/mowgli.h88
-rw-r--r--src/libmowgli/mowgli_alloc.c133
-rw-r--r--src/libmowgli/mowgli_alloc.h31
-rw-r--r--src/libmowgli/mowgli_allocation_policy.c70
-rw-r--r--src/libmowgli/mowgli_assert.h105
-rw-r--r--src/libmowgli/mowgli_config.h.in147
-rw-r--r--src/libmowgli/mowgli_exception.h37
-rw-r--r--src/libmowgli/mowgli_heap.c323
-rw-r--r--src/libmowgli/mowgli_heap.h50
-rw-r--r--src/libmowgli/mowgli_init.c49
-rw-r--r--src/libmowgli/mowgli_ioevent.c195
-rw-r--r--src/libmowgli/mowgli_ioevent.h55
-rw-r--r--src/libmowgli/mowgli_iterator.h38
-rw-r--r--src/libmowgli/mowgli_logger.c62
-rw-r--r--src/libmowgli/mowgli_mempool.c199
-rw-r--r--src/libmowgli/mowgli_mempool.h45
-rw-r--r--src/libmowgli/mowgli_spinlock.c105
-rw-r--r--src/libmowgli/mowgli_spinlock.h44
-rw-r--r--src/libmowgli/mowgli_stdinc.h96
-rw-r--r--src/libmowgli/mowgli_string.c121
-rw-r--r--src/libmowgli/mowgli_string.h48
-rw-r--r--src/libmowgli/object/Makefile21
-rw-r--r--src/libmowgli/object/class.c (renamed from src/libmowgli/mowgli_object_class.c)5
-rw-r--r--src/libmowgli/object/class.h (renamed from src/libmowgli/mowgli_object_class.h)3
-rw-r--r--src/libmowgli/object/message.c (renamed from src/libmowgli/mowgli_object_messaging.c)2
-rw-r--r--src/libmowgli/object/message.h (renamed from src/libmowgli/mowgli_object_messaging.h)2
-rw-r--r--src/libmowgli/object/metadata.c (renamed from src/libmowgli/mowgli_object_metadata.c)4
-rw-r--r--src/libmowgli/object/metadata.h (renamed from src/libmowgli/mowgli_object_metadata.h)2
-rw-r--r--src/libmowgli/object/object.c (renamed from src/libmowgli/mowgli_object.c)4
-rw-r--r--src/libmowgli/object/object.h (renamed from src/libmowgli/mowgli_object.h)2
-rw-r--r--src/libmowgli/platform/Makefile9
-rw-r--r--src/libmowgli/platform/autoconf.h.in105
-rw-r--r--src/libmowgli/platform/constructor.h (renamed from src/libmowgli/mowgli_logger.h)45
-rw-r--r--src/libmowgli/platform/machine.h334
-rw-r--r--src/libmowgli/platform/win32/Makefile15
-rw-r--r--src/libmowgli/platform/win32/fork.c166
-rw-r--r--src/libmowgli/platform/win32/gettimeofday.c (renamed from src/libmowgli/win32_support.c)4
-rw-r--r--src/libmowgli/platform/win32/inet.c80
-rw-r--r--src/libmowgli/platform/win32/pipe.c (renamed from src/libmowgli/mowgli_init.h)14
-rw-r--r--src/libmowgli/platform/win32/setenv.c (renamed from src/libmowgli/mowgli_allocator.h)16
-rw-r--r--src/libmowgli/platform/win32/socketpair.c109
-rw-r--r--src/libmowgli/platform/win32/win32_stdinc.h (renamed from src/libmowgli/win32_support.h)23
-rw-r--r--src/libmowgli/thread/Makefile18
-rw-r--r--src/libmowgli/thread/mutex.c134
-rw-r--r--src/libmowgli/thread/mutex.h79
-rw-r--r--src/libmowgli/thread/null_mutexops.c (renamed from src/libmowgli/mowgli_allocator.c)39
-rw-r--r--src/libmowgli/thread/posix_mutexops.c115
-rw-r--r--src/libmowgli/thread/thread.h78
-rw-r--r--src/libmowgli/thread/win32_mutexops.c74
-rw-r--r--src/libmowgli/vio/Makefile15
-rw-r--r--src/libmowgli/vio/vio.c140
-rw-r--r--src/libmowgli/vio/vio.h219
-rw-r--r--src/libmowgli/vio/vio_openssl.c447
-rw-r--r--src/libmowgli/vio/vio_sockets.c423
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;
+}